awcodes/filament-addons
A set of handy add-ons and reusable components that extend Filament, Laravel's admin panel framework. Quickly add extra UI elements and utilities to your forms, tables, and panels by installing via Composer and registering the plugin.
Confirm the compatibility matrix before you type composer require. The last release is 0.3.15 (Feb 2024), the package is pre-1.0, and Filament has moved through majors since. Open composer.json on the 0.3.15 tag and check the filament/filament constraint against what your app actually runs. If it lists ^3.0 and you are on Filament 4, stop here — you are signing up to fork, not to integrate.
Install with an exact pin, not a caret.
composer require awcodes/filament-addons:0.3.15
^0.3 gives you no safety on a 0.3.x line — a minor bump is allowed to rename classes. Pin exactly during the spike, and only loosen after you have a green test suite and a changelog review ritual.
Look at these three places first, in this order:
vendor/awcodes/filament-addons/src/ — the actual class list. This is ground truth. READMEs on low-traffic 0.x packages drift; the directory tree does not. Enumerate the fields, columns, and components that exist on this tag.vendor/awcodes/filament-addons/composer.json — extra.laravel.providers tells you whether the service provider is auto-discovered, and the filament constraint tells you the supported version.CHANGELOG / GitHub releases — v0.3.15 is a single fix: PR #16, "OEmbed Component Throws Error." That is your one piece of evidence-backed capability. Treat OEmbed as the reason you are here; everything else is incidental.Register the plugin (if the package ships one). If the package exposes a Filament plugin object, register it on the panel you are piloting — not globally:
// app/Providers/Filament/AdminPanelProvider.php
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugin(\Awcodes\FilamentAddons\FilamentAddonsPlugin::make());
}
If it does not ship a plugin and components are plain Filament field classes, skip registration entirely — Filament resolves them by namespace and you only need the use statement. Verify which of these is true on the tag before writing the provider change; guessing here produces a Class not found that looks like a Composer problem but is not.
Publish views/assets only if you need to override them. If the package registers publishable paths, do it selectively:
php artisan vendor:publish --tag=filament-addons-views
php artisan vendor:publish --tag=filament-addons-assets
Publishing everything up front is a common mistake — you fork the vendor's markup into your repo, and now upstream fixes never reach you.
First use case: an embed field in an editorial form. The one capability with release evidence is OEmbed. Drop it into a resource form alongside a URL input:
use Awcodes\FilamentAddons\Forms\Components\OEmbed;
public static function form(Form $form): Form
{
return $form->schema([
TextInput::make('title')->required(),
TextInput::make('video_url')
->url()
->rule('regex:/^https:\/\/(www\.)?(youtube\.com|youtu\.be|vimeo\.com)\//')
->required(),
OEmbed::make('video_url')
->label('Preview'),
]);
}
Confirm the actual class name and namespace against src/ on the tag — Forms\Components\OEmbed is the shape you should expect from a Filament field, but pre-1.0 packages relocate things between minors and this is exactly where you will burn an hour if you trust the blog post instead of the source.
Isolate the adoption to one panel and one component. The package's own maturity profile (30 stars, zero dependents, single maintainer, no release since Feb 2024) means you are the QA. Land it on an internal or editorial panel behind a feature flag, use exactly one component, and defer the rest of the addon set until a second concrete need appears. The failure mode to avoid is a component library becoming a de facto standard by attrition across every admin surface.
Treat the OEmbed field as an integration, not a styling convenience. It makes an outbound HTTP call during render. Wrap it so a cold provider cannot take down a resource page.
// app/Support/OEmbed/OEmbedResolver.php
class OEmbedResolver
{
public function resolve(string $url): ?array
{
$host = parse_url($url, PHP_URL_HOST);
if (! in_array($host, config('oembed.allowed_hosts'), true)) {
return null;
}
return Cache::remember(
'oembed:'.sha1($url),
now()->addDay(),
fn () => rescue(
fn () => Http::timeout(3)
->retry(1, 200)
->get('https://noembed.com/embed', ['url' => $url])
->throw()
->json(),
null,
report: false,
),
);
}
}
Then feed the field pre-resolved data where the component allows it, or wrap the component in your own Livewire wrapper that owns the try/catch and renders a fallback. The v0.3.15 fix closes one known exception path; it does not close the class of failure (deleted video, private video, 404, timeout, malformed JSON).
Cache aggressively, and key on the normalized URL. A table or infolist showing 50 rows with an embed column will otherwise make 50 outbound calls per render. Normalize first (strip tracking params, youtu.be → youtube.com/watch?v=) so two forms of the same URL share one cache entry.
Validate on save, not only on render. A host allow-list in a FormRequest or a field ->rule() is cheaper than discovering at render time that someone pasted a URL from an arbitrary domain:
->rule(fn () => new AllowedEmbedHostRule(config('oembed.allowed_hosts')))
This is also your SSRF boundary. Restrict the scheme to https and the host to an explicit list — do not let a URL field hand an arbitrary host to a server-side fetcher.
Test with Http::fake() so CI never touches YouTube.
public function test_oembed_field_renders_with_a_valid_url(): void
{
Http::fake([
'noembed.com/*' => Http::response([
'title' => 'Test Video',
'html' => '<iframe src="https://www.youtube.com/embed/abc"></iframe>',
]),
]);
livewire(EditPost::class, ['record' => $post->id])
->fillForm(['video_url' => 'https://www.youtube.com/watch?v=abc'])
->assertFormSet(['video_url' => 'https://www.youtube.com/watch?v=abc']);
}
public function test_oembed_field_degrades_on_provider_failure(): void
{
Http::fake(['noembed.com/*' => Http::response(null, 500)]);
// assert the page still renders and shows a fallback
}
Cover the failure cases explicitly: invalid URL, deleted video, private video, provider timeout, disallowed host. Those are the five that will page you.
Wire vendor views into your Filament theme's Tailwind content globs — and rebuild. If the package ships Blade views with Tailwind classes, your theme's tailwind.config.js must include the vendor path:
content: [
'./app/Filament/**/*.php',
'./resources/views/filament/**/*.blade.php',
'./vendor/filament/**/*.blade.php',
'./vendor/awcodes/filament-addons/resources/views/**/*.blade.php',
],
Then rebuild the theme (npm run build), not just npm run dev. This is the single most common silent failure with Filament addons: components look perfect in dev, and in the production build they render unstyled because the classes were purged. Verify in a built asset, not in the dev server.
Keep a written pin-and-review workflow. Record 0.3.15 in composer.json, name an internal owner, and put a recurring review on the calendar: upstream activity, new Filament releases, advisories on transitive dependencies. If upstream stays quiet, the fork plan is to copy the handful of class files you actually use into app/Support/ and swap the imports — that is a cheap exit only if you confined usage to one or two call sites.
^0.3 is not a stability guarantee. On a 0.3.x line, minor bumps are permitted to rename or restructure. Pin exactly, read the changelog on every bump, and treat every minor as potentially breaking. Budget the upgrade as a task, not as a composer update you run alongside thirty others.
Zero dependents means you are the first integration test. Nobody else is exercising this code against modern Filament. Regressions will surface in your admin panel first. Allocate a real compatibility spike — service provider discovery, plugin registration, published view/config tags, Tailwind globs, and a production build — before it gets absorbed into a feature estimate.
The Tailwind glob omission is invisible until production. In dev, JIT picks up classes from files it can see; in a purged production build, anything not in a content path disappears. If a component is structured correctly but looks unstyled, check the globs before you check the component.
Do not call the provider on every render. Filament re-renders on every Livewire interaction. An embed field in a form will re-fetch on each keystroke that triggers a wire:model sync unless you cache or defer. Cache with a per-URL key; consider ->lazy() or a "preview" button that resolves on demand instead of on mount.
CSP frame-src is a separate failure mode. The embed renders an <iframe> from youtube.com / player.vimeo.com. If you ship a Content-Security-Policy, add those domains to frame-src or the field will silently render an empty box that looks like a package bug. Coordinate with whoever owns the headers before the pilot, not after QA logs "embed doesn't show."
Latency during a provider outage shows up as "the admin is slow," not as "the dependency does HTTP." Set an explicit Http::timeout(3) and ->retry(1, 200). Without a timeout, a hung connection blocks the Livewire request until PHP's default socket timeout — which is long enough to look like a dead admin panel.
Validate scheme and host on save. An embed field that fetches a user-supplied URL server-side is an SSRF surface. Restrict to https and an explicit host allow-list, and reject everything else at validation time with a clear message rather than at render time with a stack trace.
Publish selectively, not wholesale. Running vendor:publish with no --tag dumps every publishable view and config into your repo. You now own markup you did not write and will not maintain, and upstream fixes will never reach you. Publish one view, only when you actually need to override it.
Verify class names against the tag, not the README. Filament field classes follow a consistent shape (Forms\Components\*, Tables\Columns\*), but pre-1.0 packages move things between minors. grep -r "class OEmbed" vendor/awcodes/filament-addons/src takes ten seconds and saves an hour of debugging a Class "..." not found that looks like a Composer autoload issue.
A ~40-line custom Filament component may genuinely beat this dependency. If OEmbed is the only thing you need, weigh it honestly: a field that extends Filament's base component, does one cached Http::get, and renders an iframe is small, owned, tested, and has no bus factor. The dependency's value is the collection of components — if you are using one, the build-vs-buy math tilts toward building.
Keep the integration behind a flag until staging is clean. Smoke-test representative URLs plus the five failure cases on a built asset. If the package is load-bearing for a customer-facing surface — or the embedded media is revenue-linked or compliance-relevant — this is the wrong tool and you should own the integration outright.
How can I help you explore Laravel packages today?