Colors
The Acun UI palette. Components use Tailwind's color names (brand, gray, zinc, emerald…); the @theme block in panel.css sets their values. Each color's light and dark shades are derived from a single base value with color-mix, so changing a color takes a single line.
Palette
The @theme values in panel.css.
| Color | Token | Value | Usage |
|---|---|---|---|
| Primary | brand-600 |
#696bfe |
Buttons, links, selected states |
| Accent | accent-500 |
#ec4899 |
Menu badges, small accents |
| Success | emerald-500 |
#42d697 |
Confirmation, completed, active |
| Info | sky-500 |
#45b8f4 |
Informational messages |
| Warning | amber-500 |
#f9c74f |
States that need attention |
| Danger | red-500 |
#fe696a |
Deletion, errors, inactive |
| Secondary | secondary-500 |
#8592a3 |
Gray button, soft-secondary |
| Dark | dark |
#2b2c40 |
Dark button |
| Light | light |
#f5f5f9 |
Light button, light-theme page background |
| Ink | gray-900 |
#16162a |
Headings, dark surfaces |
| gray-50 | --color-gray-50 |
#f7f7fb |
Page background |
| gray-100 | --color-gray-100 |
#f0f0f6 |
Hover |
| gray-200 | --color-gray-200 |
#e4e4ee |
Border |
| gray-300 | --color-gray-300 |
#cfd0de |
Strong border |
| gray-400 | --color-gray-400 |
#85879c |
Muted text |
| gray-500 | --color-gray-500 |
#5f6177 |
Secondary text |
| gray-600 | --color-gray-600 |
#46485b |
Icon |
| gray-700 | --color-gray-700 |
#313244 |
Body text |
| gray-800 | --color-gray-800 |
#26273a |
|
| gray-900 | --color-gray-900 |
#16162a |
Heading (ink) |
| zinc-950 | --color-zinc-950 |
#0a0a0a |
Page background |
| zinc-900 | --color-zinc-900 |
#141414 |
Surface (card, menu) |
| zinc-800 | --color-zinc-800 |
#1f1f1f |
Hover, field |
| zinc-700 | --color-zinc-700 |
#2e2e2e |
Border |
| zinc-600 | --color-zinc-600 |
#474747 |
Strong border |
| zinc-500 | --color-zinc-500 |
#8c8c8c |
Muted text |
| zinc-400 | --color-zinc-400 |
#b4b4b4 |
Secondary text |
| zinc-300 | --color-zinc-300 |
#d4d4d4 |
Body text |
| zinc-200 | --color-zinc-200 |
#e5e5e5 |
|
| zinc-100 | --color-zinc-100 |
#f5f5f5 |
Heading |
| default | brand-color="default" |
#696bfe |
Default |
| green | brand-color="green" |
#42d697 |
Green |
| red | brand-color="red" |
#fe696a |
Red |
| yellow | brand-color="yellow" |
#f9c74f |
Yellow |
| blue | brand-color="blue" |
#45b8f4 |
Blue |
| gray | brand-color="gray" |
#8592a3 |
Gray |
| dark | brand-color="dark" |
#2b2c40 |
Dark |
Semantic colors and shades
Each semantic color has eleven shades from 50 to 950, all derived from a single base value: brand-600 for the primary color, and the palette color's 500 shade for the others (emerald-500, sky-500, amber-500, red-500). Because these colors are light, shades 600 and up mix in more black so they stay legible: use 50–100 on light backgrounds, 500 for fills and icons, and 600–700 for text.
<div class="space-y-3">
@foreach (['brand' => 'Primary', 'emerald' => 'Success', 'sky' => 'Info', 'amber' => 'Warning', 'red' => 'Danger'] as $color => $name)
<div class="grid grid-cols-[6rem_1fr] items-center gap-3">
<span class="text-xs font-medium text-gray-500 dark:text-zinc-400">{{ $name }}</span>
<div class="grid grid-cols-11 overflow-hidden rounded-sm">
@foreach ([50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as $shade)
<span class="h-9" style="background: var(--color-{{ $color }}-{{ $shade }})" title="{{ $color }}-{{ $shade }}"></span>
@endforeach
</div>
</div>
@endforeach
</div>
| Prop | Values |
|---|---|
brand · emerald · sky · amber · red | 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 950 |
Text and surface colors
The light theme uses the gray neutrals, the dark theme the zinc neutrals. Write every class together with its dark: counterpart: headings text-gray-900 dark:text-zinc-100, body text-gray-700 dark:text-zinc-300, secondary text text-gray-500 dark:text-zinc-400, card background bg-white dark:bg-zinc-900.
<div class="grid gap-4 sm:grid-cols-2">
<div class="space-y-1 rounded-sm bg-white p-4 shadow-sm dark:bg-zinc-900">
<p class="text-sm font-semibold text-gray-900 dark:text-zinc-100">Heading · gray-900 / zinc-100</p>
<p class="text-sm text-gray-700 dark:text-zinc-300">Body text · gray-700 / zinc-300</p>
<p class="text-sm text-gray-500 dark:text-zinc-400">Secondary text · gray-500 / zinc-400</p>
<p class="text-sm text-gray-400 dark:text-zinc-500">Muted text · gray-400 / zinc-500</p>
</div>
<div class="space-y-1 rounded-sm border border-gray-200 bg-gray-50 p-4 text-sm dark:border-zinc-700 dark:bg-zinc-950">
<p>Page background · gray-50 / zinc-950</p>
<p>Border · gray-200 / zinc-700</p>
<p class="rounded-sm px-2 py-1 hover:bg-gray-100 dark:hover:bg-zinc-800">Hover · gray-100 / zinc-800</p>
</div>
</div>
| Prop | Values |
|---|---|
gray-* | Light-theme neutrals |
zinc-* | Dark-theme neutrals (with dark:) |
Status colors
Components show statuses with a light background (50) and dark text (700); in the dark theme the background is at 10% opacity and the text uses the 400 shade. The info color is sky in every component: alerts, badges, avatars, stat cards, timelines and the info look of the soft-info button all use the same shades. Brand accents that do not indicate a status (e.g. a "New" badge) use the brand shades.
<div class="flex flex-wrap gap-2 text-sm">
<span class="rounded-sm bg-emerald-50 px-3 py-2 text-emerald-700 dark:bg-emerald-500/10 dark:text-emerald-400">Delivered</span>
<span class="rounded-sm bg-amber-50 px-3 py-2 text-amber-700 dark:bg-amber-500/10 dark:text-amber-400">Pending</span>
<span class="rounded-sm bg-red-50 px-3 py-2 text-red-700 dark:bg-red-500/10 dark:text-red-400">Canceled</span>
<span class="rounded-sm bg-sky-50 px-3 py-2 text-sky-700 dark:bg-sky-500/10 dark:text-sky-400">Notified</span>
<span class="rounded-sm bg-brand-50 px-3 py-2 text-brand-700 dark:bg-brand-500/10 dark:text-brand-300">New record</span>
</div>
| Prop | Values |
|---|---|
Light theme | bg-{color}-50 text-{color}-700 |
Dark theme | dark:bg-{color}-500/10 dark:text-{color}-400 |
Accent color
accent (pink) is only for small accents: the count badges in the menu and the underline of the active page in the horizontal menu. Only the 50, 100, 500 and 600 shades are defined for this color; do not use it on buttons or large surfaces.
<div class="flex flex-wrap items-center gap-8">
<span class="h-0.5 w-10 rounded-full bg-accent-500"></span>
<span class="rounded-full bg-accent-50 px-1.5 font-mono text-2xs font-medium tabular-nums text-accent-600 dark:bg-accent-500/15 dark:text-accent-500">12</span>
</div>
| Prop | Values |
|---|---|
accent-* | 50 | 100 | 500 | 600 |
Letting users pick the primary color
acun:brand-color-picker shows seven preset colors and a free color picker. The choice is applied to the entire interface immediately and stored in the browser; if the chosen color is too light for white text to be legible, a warning appears.
<acun:brand-color-picker label="Primary color" />
| Prop | Values |
|---|---|
label | Heading and the accessible name of the group |
custom | true | false (free color picker) |
presets | key => [hex, name] array |
Saving the preference to the account
Layouts apply the user's saved color (a preset name or #rrggbb) through the brand-color prop before the first paint. When preference-url is set, the color picker sends each new choice to that URL as { brand }; otherwise the preference stays in the browser only.
<acun:layout.sidebar
:brand-color="auth()->user()->brand_color"
preference-url="{{ route('ui-preference.update') }}"
>
…
</acun:layout.sidebar>
{{-- Server-side validation: ['brand' => ['regex:/^(#[0-9a-fA-F]{6}|default|green|red|yellow|blue|gray|dark)$/']] --}}
| Prop | Values |
|---|---|
brand-color | default | green | red | yellow | blue | gray | dark | #rrggbb |
preference-url | POST URL where the preference is saved |
Changing the primary color
For a different primary color across the whole application, change only the --color-brand-600 value in your CSS; the other brand-* shades are derived from it. Preset colors the user picks override this value through the data-brand-color attribute on the html element.
/* app.css — after the @import '@acunsoft/acun-ui-core'; line */
@theme {
--color-brand-600: #0f766e;
}
| Prop | Values |
|---|---|
--color-brand-600 | Base value of the primary color |
data-brand-color | Preset color name (html attribute) |
Props and slots
The values the component accepts.
| Prop | Default | Description |
|---|---|---|
--color-brand-600 | #696bfe | Primary color; brand-50 … 950 are derived from it |
--color-accent-500 | #ec4899 | Accent; accent-50, 100 and 600 are derived from it |
--color-emerald-500 | #42d697 | Base of the success shades |
--color-sky-500 | #45b8f4 | Base of the info shades |
--color-amber-500 | #f9c74f | Base of the warning shades |
--color-red-500 | #fe696a | Base of the danger shades |
--color-secondary-500 | #8592a3 | Base of the secondary (gray) shades |
--color-dark · --color-light | #2b2c40 · #f5f5f9 | Dark and light buttons; light is also the light-theme page background |
--btn-{variant}-* | panel.css | Background, border, hover and shadow colors of solid buttons |
data-brand-color | default | html attribute: default · green · red · yellow · blue · gray · dark · custom |
brand-color-picker: presets | 7 preset colors | key => [hex, name]; the key becomes the data-brand-color value |
brand-color-picker: custom | true | Shows the free color picker |
brand-color-picker: label | null | Heading above; when empty, the group name is "Primary color" |