Search

Theming Filament: Custom Colors, Fonts and Dark Mode

Theming Filament: Custom Colors, Fonts and Dark Mode

Key takeaways

  • ✓ Most branding happens in the panel provider without any CSS: ->colors(), ->font(), ->brandLogo(), ->favicon(), ->darkMode().
  • ✓ Create a custom theme (php artisan make:filament-theme) when you need your own Tailwind classes or CSS overrides. Since Filament v4, themes use Tailwind CSS v4 with @source rules.
  • ✓ Style Filament through its CSS hook classes (.fi-…) and render hooks, not by publishing and editing vendor Blade views.
  • ✓ For a completely different look, official themes (Soft, Sharp, Noir, Compact) and community themes install in minutes.

An unbranded Filament panel looks good, and exactly like every other Filament panel. Clients notice. The good news is that most branding needs no CSS at all, and when you do need CSS, Filament v5 gives you stable hooks instead of making you fork its views. This guide works from the panel provider down to a full custom theme.

Also Read: Filament vs Nova vs Backpack (2026): An Honest Comparison

Level 1: Panel provider branding (no CSS)

Colours

Filament uses six semantic colours: primary, gray, info, success, warning and danger. Set them per panel:

use Filament\Support\Colors\Color;

public function panel(Panel $panel): Panel
{
    return $panel
        ->colors([
            'primary' => Color::hex('#0F766E'),   // your brand teal
            'gray' => Color::Slate,
            'danger' => Color::Rose,
            'info' => Color::Sky,
            'success' => Color::Emerald,
            'warning' => Color::Amber,
        ]);
}

Color::hex() and Color::rgb() generate a full 50–950 palette from one brand colour, so buttons, badges, focus rings and charts all match. Every Tailwind colour (Color::Indigo, Color::Zinc and so on) is available as a constant. Choosing a cool gray like Slate or a warm one like Stone changes the whole panel more than you’d expect.

To add your own colour names (for example brand or premium) for badges and buttons across all panels, register them globally in a service provider with FilamentColor::register([...]).

Also Read: Laravel and PHP

Fonts

->font('Inter')

Filament loads fonts from Bunny Fonts by default, a GDPR-friendly Google Fonts mirror. Use Google directly or self-host instead:

use Filament\FontProviders\GoogleFontProvider;
use Filament\FontProviders\LocalFontProvider;

->font('Inter', provider: GoogleFontProvider::class)

->font('Brand Sans', url: asset('fonts/brand-sans.css'), provider: LocalFontProvider::class)

Self-host if you have strict privacy or CSP requirements, or a licensed brand font.

Logo and favicon

->brandName('Acme Ops')
->brandLogo(asset('images/logo-light.svg'))
->darkModeBrandLogo(asset('images/logo-dark.svg'))
->brandLogoHeight('2rem')
->favicon(asset('images/favicon.png'))

brandLogo() also accepts HTML, including a Blade view with an inline SVG. That’s handy if you want the logo to use currentColor.

Also Read: Laravel and PHP

Dark mode

Filament follows the operating system’s light or dark preference by default. You can change that:

use Filament\Enums\ThemeMode;

->darkMode(false)                        // light only
->darkMode(isForced: true)               // dark only
->defaultThemeMode(ThemeMode::Light)     // default light, users can switch
->themeSwitcher(false)                   // keep dark mode, hide the switcher

Before disabling dark mode, remember that admins stare at panels all day. Keep it, and test your custom views in both modes.

Layout options

A few layout settings change how the panel feels:

->sidebarCollapsibleOnDesktop()
->topNavigation()                        // horizontal nav instead of a sidebar
->maxContentWidth(\Filament\Support\Enums\Width::Full)
->spa()                                  // SPA-style navigation with wire:navigate

Level 2: A custom theme (Tailwind CSS v4)

You need a custom theme when you:

  • use Tailwind classes in your own Blade views, custom fields, columns or pages,
  • want to override Filament’s styles with CSS, or
  • install a theme plugin that asks you to import its CSS.

That first point catches people out. Since v4, Filament no longer ships its Tailwind utility classes in the default stylesheet, so classes like text-primary-600 in your own views silently do nothing without a theme.

php artisan make:filament-theme   # or: make:filament-theme admin

The command installs Tailwind CSS v4, creates resources/css/filament/admin/theme.css, adds it to vite.config.js, and registers it on the panel with ->viteTheme(). If it can’t edit your files automatically, do it by hand:

->viteTheme('resources/css/filament/admin/theme.css')

The theme file:

@import '../../../../vendor/filament/filament/resources/css/theme.css';

@source '../../../../app/Filament/**/*';
@source '../../../../resources/views/filament/**/*';
@source '../../../../resources/views/components/**/*';
@source '../../../../app/Livewire/**/*';

@source tells Tailwind v4 where to look for class names, replacing the old content array in tailwind.config.js. You don’t need to add vendor/filament, but check plugin READMEs, because some need their own @source or @import.

Also Read: Laravel: Filament Blueprint Review

Build it:

npm run build   # or npm run dev while working

Level 3: Targeted CSS with hook classes

Filament puts stable fi- classes on its components, called CSS hooks, specifically so you can style them without touching views. Use browser dev tools to find them, then write CSS in your theme:

/* Tighter table rows for data-heavy panels */
.fi-ta-text:not(.fi-inline) {
    @apply sm:py-2;
}

/* Brand the sidebar */
.fi-sidebar {
    @apply bg-gray-50 dark:bg-gray-950;
}

/* Rounder buttons across the panel */
.fi-btn {
    @apply rounded-full;
}

Keep overrides small and specific. Hook classes are stable, but deep descendant selectors that depend on internal markup can break in minor releases.

Level 4: Render hooks for extra UI

To add markup, such as a staging banner, a support widget or a footer, use render hooks instead of editing layouts:

use Filament\View\PanelsRenderHook;
use Illuminate\Support\Facades\Blade;

->renderHook(
  PanelsRenderHook::BODY_START,
  fn (): string => app()->environment('production')
    ? ''
    : Blade::render('<div >STAGING: data resets nightly</div>'),
)
->renderHook(
  PanelsRenderHook::FOOTER,
  fn () => view('filament.footer'),
)

There are hooks for the topbar, sidebar, user menu, page header, auth pages and more. For a polished environment badge without writing it yourself, pxlrbt/filament-environment-indicator (Filament 4 and 5) does exactly that.

Also Read: Claude Code & Cursor on Filament: AI Agent Rules That Work - Laravel

Why not publish Filament’s views?

You can, and you’ll regret it at the next update. Published views are frozen copies that miss upstream fixes and break in subtle ways when the component API moves. CSS hooks, render hooks and custom components are the supported extension points.

Level 5: Ready-made themes

If you want a different visual language rather than a recoloured one:

Also Read: What Is Jev? TypeSafe AI's 'System One' Model Explained (Pricing, API & Use Cases)

ThemePriceVersionsStyle
Soft (official)$39v4, v5Serif headings, filled fields, pill-shaped actions
Sharp (official)$39v4, v5Square corners and fine rules for data-heavy tools
Noir (official)$39v4, v5Dark-first, layered near-black surfaces
Compact (official)$29v4, v5Denser spacing, more rows on screen
Nord (Andréia Bohner)Free (MIT)3.x→v5Arctic Nord palette, light and dark
Cotton Candy (Andréia Bohner)€39v4, v5Pastel palettes, rounded and soft

Prices are from the official theme marketplace and plugin pages in September 2026. We compare more options, including starter kits, in best Filament themes and starter kits.

Per-panel and per-user theming

  • Per panel: each panel provider has its own colours, font and viteTheme(), so an internal /admin panel and a customer /app panel can look completely different.
  • Per user: the free UI Switcher plugin (Filament 4.1+ and 5) lets each user choose a primary colour, font, text size and layout, stored in the session or the database.
  • Per tenant (white-label): resolve colours at runtime. ->colors() accepts values you compute, so you can read a tenant’s brand colour in middleware and apply it with FilamentColor::register() before the panel renders.

Checklist before you ship a theme

  1. Test light and dark mode on every custom view.
  2. Check contrast (WCAG AA) for your primary colour on white and on gray-900.
  3. Run npm run build in CI, not on the server.
  4. Verify that plugin styles still render (missing @source entries are the usual culprit).
  5. Screenshot key pages before and after Filament updates to catch CSS regressions.

FAQ

How do I change the primary colour in Filament?

Call ->colors(['primary' => Color::hex('#yourhex')]) in your panel provider. Filament generates the full shade palette automatically.

Why don’t my Tailwind classes work in Filament v4/v5?

Filament no longer includes its utility classes in the default CSS. Create a custom theme with php artisan make:filament-theme and add @source entries for the folders containing your views.

How do I disable dark mode in Filament?

Use ->darkMode(false) on the panel. To force dark mode, use ->darkMode(isForced: true). To keep it but hide the toggle, use ->themeSwitcher(false).

Can I use a different font in Filament?

Yes. Use ->font('Font Name'). It loads from Bunny Fonts by default. Pass GoogleFontProvider::class, or LocalFontProvider::class with a stylesheet URL, to change the source.

Sources and further reading

Related on The Web Tier: Custom Filament form fields

TWT Staff

TWT Staff

Writes about Programming, tech news, discuss programming topics for web developers (and Web designers), and talks about SEO tools and techniques

Your experience on this site will be improved by allowing cookies Cookie Policy