trinity/widgets
Trinity Widgets is a Laravel package for building reusable, configurable UI widgets with a simple PHP API. Compose dashboards and page components quickly, keep markup consistent, and extend widgets as your app grows.
Given the package's age (last release September 2017) and near-zero adoption, treat "getting started" as an evaluation exercise first and an integration second.
composer.json in the repo for illuminate/support and php requirements before running composer require trinity/widgets. On Laravel 8+ you will almost certainly need --ignore-platform-reqs or a local path/VCS repository with a forked constraint.src/ before you publish anything. Look for the service provider (likely Trinity\Widgets\WidgetsServiceProvider), a base Widget/AbstractWidget class, and any config/widgets.php. These three files tell you the entire API surface — the package is small enough to read end-to-end in ten minutes.php artisan vendor:publish --provider="Trinity\Widgets\WidgetsServiceProvider"
Published views usually land in resources/views/vendor/widgets — that directory is where you customize output rather than editing vendor files.If step 1 or step 4 fails, stop. There is no maintainer to file an issue with, and no dependents to consult.
The package follows the standard Laravel "renderable view object" shape, so patterns mirror what you'd write yourself with view composers — which is the point: use its conventions, don't fight them.
Defining a widget. Create a class extending the package's base widget, typically with a render() or data() method plus a view name:
namespace App\Widgets;
use Trinity\Widgets\Widget;
class ActiveUsers extends Widget
{
protected $view = 'widgets.active-users';
public function data(): array
{
return ['count' => User::where('last_seen', '>', now()->subMinutes(5))->count()];
}
}
Registering. Depending on how the package is built, widgets are either registered in config/widgets.php under a keyed map, or resolved by class name at render time. Read the provider's register()/boot() to know which — the config-driven approach is more common and lets you alias widgets ('active-users' => ActiveUsers::class).
Rendering from Blade. Expect a helper or directive such as @widget('active-users') or {!! widget('active-users', ['limit' => 5]) !!}. Pass parameters as an array; the base class usually merges them into the view data. Keep parameter arrays small and typed — there's no validation layer in a package this size.
Wrapping for safety. Because the package is unmaintained, define your own thin interface (interface DashboardWidget { public function data(): array; }) and have your widget classes implement it. The Trinity base class becomes an implementation detail you can swap out in an afternoon if you need to replace the package.
Caching. Any widget hitting the database should cache inside data(), not rely on the package:
return Cache::remember('widget.active-users', 60, fn () => [...]);
If the package offers its own cache flag, verify it actually keys on parameters — a 2017-era implementation may not.
Illuminate\Contracts namespace moves, now()/Carbon 2 changes, removal of array_get/str_* helpers (deprecated in 5.8, removed in 6), and Blade directive registration changes. Grep the source for array_get, str_, and studly before upgrading Laravel.dont-discover / auto-discovery conventions, you may need to manually add the provider to config/app.php. Check whether extra.laravel.providers exists in its composer.json.widgets:: namespace, confirm it doesn't clash with your own resources/views/widgets. Published views silently override package views, which is desirable — but stale published copies won't pick up package fixes (there won't be any, so this is moot, but the same trap applies to your fork).@widget directive registered in boot() must run before views compile. If you see @widget rendered literally, you're hitting a cached compiled view — run php artisan view:clear.WidgetRenderer service in your app that calls into Trinity for the simple case and falls back to your own implementation for anything non-trivial. That gives you a migration path that doesn't require a big-bang rewrite.LICENSE file is the only thing standing between you and a clean fork.How can I help you explore Laravel packages today?