Theme Authoring
A FilamentCraft theme is one PHP class that declares the settings panel your end-users see in the editor — Colors, Typography, Buttons, Inputs, Boxes, and anything else you want to expose. The package ships one default theme (StudioTheme) with a 9-category panel. Custom themes coexist alongside it or replace it entirely.

On this page vs. its siblings
| Page | Covers |
|---|---|
| Theme Authoring (here) | Create a theme class, register it, and consume its CSS variables. |
| Color Schemes | The ColorSchemeGroup system — 14 built-in schemes, OkLch shades, per-site persistence. |
| Live Preview | How edits patch the iframe, live-update modes, and where values are stored. |
| Setting Types | Every input you can place in a theme schema. |
1. Create the theme class
Place it in app/Themes/AcmeTheme.php and extend AbstractTheme. A theme's settingsSchema() returns top-level Category groups, each holding setting types:
<?php
namespace App\Themes;
use FilamentCraft\Settings\Types\Category;
use FilamentCraft\Settings\Types\Checkbox;
use FilamentCraft\Settings\Types\ColorSchemeGroup;
use FilamentCraft\Settings\Types\Font;
use FilamentCraft\Settings\Types\Range;
use FilamentCraft\Theming\AbstractTheme;
final class AcmeTheme extends AbstractTheme
{
public function slug(): string
{
return 'acme';
}
public function name(): string
{
return 'Acme';
}
public function settingsSchema(): array
{
return [
Category::make('colors')
->label('Colors')
->icon('heroicon-o-swatch')
->collapsed(false) // open by default; categories are collapsed otherwise
->settings([
ColorSchemeGroup::make('color_scheme')->default('light'),
]),
Category::make('typography')
->label('Typography')
->icon('heroicon-o-language')
->settings([
Font::make('default_font')->cssVar('--font-default')->default('inter'),
Font::make('heading_font')
->cssVar('--font-heading')
->onlyCategory(['display', 'serif'])
->default('playfair-display'),
Range::make('body_size')
->cssVar('--font-body-size', 'px')
->unit('px')->min(12)->max(20)->default(16),
]),
Category::make('buttons')
->label('Buttons')
->icon('heroicon-o-cursor-arrow-rays')
->settings([
Range::make('button_radius')
->cssVar('--button-radius', 'px')
->unit('px')->min(0)->max(24)->default(8),
Checkbox::make('button_uppercase')
->cssVar('--button-text-transform')
->cssValues('uppercase', 'none')
->default(false),
]),
];
}
}AbstractTheme also gives you optional overrides: description(), previewImage(), stylesheets(), and scripts().
2. Register it
Two equivalent ways — pick whichever fits your setup.
A. Via config/filamentcraft.php (recommended — works for panel routes and public preview/site routes):
'themes' => [
'paths' => [],
'builtin_enabled' => true, // ship StudioTheme alongside; set false to replace it
'register' => [
\App\Themes\AcmeTheme::class,
],
],B. Via the plugin's fluent API (panel-only — for themes that should render only inside Filament admin, not on public pages):
use FilamentCraft\FilamentCraftPlugin;
public function panel(Panel $panel): Panel
{
return $panel->plugin(
FilamentCraftPlugin::make()
->registerTheme(\App\Themes\AcmeTheme::class)
->withoutBuiltinThemes() // optional — drop StudioTheme so only Acme appears
);
}Then create a Theme Eloquent row whose slug matches ('acme') and assign your Site to it.
3. Consume the variables in your CSS
Every cssVar() declaration is emitted into <style id="fc-tokens"> on :root of the rendered iframe / public page:
.btn {
border-radius: var(--button-radius);
text-transform: var(--button-text-transform);
font-size: var(--font-body-size);
font-family: var(--font-default);
}If you use Tailwind v4, map them into utility classes via @theme inline so bg-primary, text-on-primary, etc. work in your section blades:
@theme inline {
--font-default: var(--font-default);
--font-heading: var(--font-heading);
--color-primary: var(--color-primary);
--color-primary-50: var(--color-primary-50);
--color-primary-500: var(--color-primary-500);
--color-primary-900: var(--color-primary-900);
}ColorSchemeGroup automatically emits Tailwind-style 11-step OkLch shades (--color-primary-50…950) for every non-on-* token of the active scheme — so bg-primary-600 and hover:bg-primary-700 work natively. The full color system is on the Color Schemes page.
4. Reading values programmatically
To read or write theme settings outside the editor (migrations, seeds, API endpoints):
use FilamentCraft\Support\SiteThemeSettings;
// Read merged values (overrides + schema defaults).
$values = SiteThemeSettings::values($site, $site->theme->templateSettings());
// Write a partial set (diffs against defaults; values matching default aren't stamped).
SiteThemeSettings::sync($site, $schema, ['button_radius' => 12]);Where these land — and how authored color schemes persist separately — is covered in Live Preview → Persistence.
Reference
- Canonical theme:
src/Theming/Themes/StudioTheme.php— the 9-category default panel. - Theme contract:
FilamentCraft\Theming\ThemeContract(extendAbstractThemefor sensible defaults:description,previewImage,stylesheets,scripts). - Setting base:
FilamentCraft\Settings\Setting—cssVar(),default(),label(),info(),required(),visibleIf().
