Documentation is available on GitHub Pages.
FluxUI theme and appearance settings with color swatch pickers for Laravel applications using Livewire Flux.
composer require agenticmorf/fluxui-themeRun the migration:
php artisan migrateThe App default accent swatch and live preview use config('fluxui-theme.defaults.accent'). Publish or merge config so it matches your app’s CSS accent (for example orange).
- Laravel 11+
- Livewire 3+
- Livewire Flux 2+
- Livewire Volt 1+
- Theme mode: Light, dark, or system
- Accent color swatches: 19 Flux accent colors
- Base color swatches: 10 Flux base colors (slate, gray, zinc, neutral, stone, mauve, olive, mist, taupe)
- User preferences stored in
appearance_preferencesJSON on User model
Your app must import Flux CSS and ensure base colors (slate, gray, zinc, neutral, stone, mauve, olive, mist, taupe) are available. Flux provides these via its dist; base color switching works by remapping --color-zinc-* to the chosen base.
In resources/css/app.css (or equivalent):
@import 'tailwindcss';
@import '../../vendor/livewire/flux/dist/flux.css';
/* Flux stubs for component class discovery */
@source '../../vendor/livewire/flux/stubs/**/*.blade.php';
@custom-variant dark (&:where(.dark, .dark *));The package’s appearance component injects inline CSS when a non-zinc base is selected, redefining --color-zinc-50 through --color-zinc-950 to the chosen base (e.g. --color-slate-50, etc.). Flux’s flux.css must define those base color variables.
Include the appearance component before @fluxAppearance in your layout’s <head> so theme and base color are applied before Flux initializes:
{{-- In resources/views/partials/head.blade.php or your main layout <head> --}}
@vite(['resources/css/app.css', 'resources/js/app.js'])
<x-fluxui-theme::appearance />
@fluxAppearanceWrap your main app shell with <flux:accent> so accent colors apply. Pass the effective accent from AppearanceService.
Set id="flux-accent" on that component. Flux renders a plain <div> with no id by default; the appearance settings page injects live preview CSS that targets #flux-accent, so without this id the swatch picker will not update the UI in real time.
@php
$appearance = app(\AgenticMorf\FluxuiTheme\AppearanceService::class)->getEffective(auth()->user());
@endphp
<body>
<flux:accent id="flux-accent" :color="$appearance['accent']">
{{-- Your app content: sidebar, header, main, etc. --}}
</flux:accent>
</body>Use this in layouts that render authenticated UI (e.g. components/layouts/app/sidebar.blade.php, header.blade.php, or a shared app layout).
Add a link to the appearance settings page in your settings layout. The route name is configurable (default appearance.edit):
<flux:navlist.item :href="route('appearance.edit')" wire:navigate>{{ __('Appearance') }}</flux:navlist.item>The appearance page expects a settings layout component that provides $heading, $subheading, and a $slot. For example:
{{-- x-settings.layout --}}
<div class="flex items-start max-md:flex-col">
<div class="me-10 w-full pb-4 md:w-[220px]">
<flux:navlist>
{{-- ... other nav items ... --}}
<flux:navlist.item :href="route('appearance.edit')" wire:navigate>{{ __('Appearance') }}</flux:navlist.item>
</flux:navlist>
</div>
<div class="flex-1 self-stretch max-md:pt-6">
<flux:heading>{{ $heading ?? '' }}</flux:heading>
<flux:subheading>{{ $subheading ?? '' }}</flux:subheading>
<div class="mt-5 w-full max-w-lg">{{ $slot }}</div>
</div>
</div>The Volt component optionally includes partials.settings-heading for a shared settings page header. Create it if you use a common settings layout:
{{-- resources/views/partials/settings-heading.blade.php --}}
<div class="relative mb-6 w-full">
<flux:heading size="xl" level="1">{{ __('Settings') }}</flux:heading>
<flux:subheading size="lg" class="mb-6">{{ __('Manage your profile and account settings') }}</flux:subheading>
<flux:separator variant="subtle" />
</div>If the partial does not exist, it is skipped.
Add the cast for appearance_preferences:
protected $casts = [
'appearance_preferences' => 'array',
];The migration adds the appearance_preferences column automatically when you run php artisan migrate.
Publish the config:
php artisan vendor:publish --tag=fluxui-theme-configTo use app-level defaults (e.g. from a settings table), set appearance_resolver in config/fluxui-theme.php:
'appearance_resolver' => [App\Services\MorfSettings::class, 'getAppearance'],The resolver should return ['accent' => string, 'base' => string, 'theme' => string].
By default the appearance page is at settings/appearance with route name appearance.edit. Override in config:
'route' => 'settings/appearance',
'route_name' => 'appearance.edit',Get effective appearance for the current user:
$appearance = app(\AgenticMorf\FluxuiTheme\AppearanceService::class)->getEffective(auth()->user());
// ['accent' => 'blue', 'base' => 'zinc', 'theme' => 'system']If your app already adds appearance_preferences to the users table, you can keep that migration: this package’s migration checks for the column before adding it, so running both is safe.
If the column is missing at runtime, run php artisan migrate (see installation for deploy notes).
MIT