Directives & settings

Theme and variants

Declare tokens, mode values, managed keyframes and reusable conditions.

Theme directives register token values and managed animations. @mode registers activation branches; @custom-variant registers utility selector and condition transformations. Their definitions become compiler input; only resources required by the resulting stylesheet are emitted, unless marked static.

@theme

Defines theme tokens and managed keyframes. Token names keep their leading --; Master CSS uses the name after -- for namespace resolution. The native rule below uses the token, so its variable is included in the result.

A token used by a native rule
Source
@theme {  --color-brand: #4f46e5;}.card {  background-color: var(--color-brand);}
Result
.card {  background-color: var(--color-brand);}@layer theme {  :root,  :host {    --color-brand: #4f46e5  }}

@theme <mode>

Defines mode-specific token values. The final manifest must contain a matching @mode definition. Repeated token declarations merge, with later values replacing the same token; they never infer an activation selector or add color-scheme.

One token in two modes
Source
@mode dark {  @media (prefers-color-scheme: dark) {    :root, :host { @slot; }  }}@theme {  --color-panel: white;}@theme dark {  --color-panel: #111827;}.card {  background-color: var(--color-panel);}
Result
.card {  background-color: var(--color-panel);}@layer theme {  :root,  :host {    --color-panel: white  }  @media (prefers-color-scheme:dark) {    :root {      --color-panel: #111827    }  }  @media (prefers-color-scheme:dark) {    :host {      --color-panel: #111827    }  }}

@mode

Defines where a named mode is active, separately from its token values:

CSS
@mode ocean {  [data-theme="ocean"] {    @slot;  }}@theme {  --color-surface: white;}@theme ocean {  --color-surface: #082f49;}

Each branch must contain an element selector and a bare @slot;. Branches may nest selectors, @media, and @supports. Declarations, pseudo-elements, @container, layers, and recursive mode references are rejected. A later same-name @mode replaces the entire activation definition and moves its cascade position to that definition's source order.

Token declarations appear on each activation selector. An @ocean utility matches the activation element and its descendants through a zero-specificity :where() guard. Nested token values inherit normally. Overlapping modes follow the cascade; there is no nearest-mode exclusion or JavaScript state machine. Use explicit :host(...) branches in a shadow tree. Selectors do not cross native shadow or slot boundaries. Base @theme resources target :root and :host.

CSS
@mode dark {  @media (prefers-color-scheme: dark) {    :root:not([data-theme]) {      @slot;    }  }  [data-theme="dark"] {    @slot;  }}@mode light {  @media (prefers-color-scheme: light) {    :root:not([data-theme]) {      @slot;    }  }  [data-theme="light"] {    @slot;  }}/* Native declarations explicitly control browser-provided UI. */:root {  color-scheme: light dark;}[data-theme="light"] {  color-scheme: light;}[data-theme="dark"] {  color-scheme: dark;}

The preset supplies explicit system-preference light/dark branches and base values. Override both modes for manual switching. Breakpoints, modes, and custom variants share a namespace: a cross-category duplicate is an error.

@theme inline

Defines utility shorthands that are written directly into generated declarations instead of emitting CSS custom properties. Inline tokens cannot be mode-specific. Compare this result with the variable-backed token above.

An inline token
Source
@theme inline {  --color-brand: #4f46e5;}.card {  @compose bg-brand;}
Result
.card {  background-color: #4f46e5}

@theme static

Emits the token or managed keyframes as initial CSS resources instead of waiting for a matching class to use them. inline and static cannot be combined.

A resource without a matching class
Source
@theme static {  --color-brand: #4f46e5;  @keyframes fade-in {    to { opacity: 1; }  }}
Result
@layer theme {  :root,  :host {    --color-brand: #4f46e5  }}@keyframes fade-in {  to {    opacity: 1  }}

@custom-variant

Defines reusable utility selector transformations and conditions. Branches can combine selectors such as &:hover with native conditional wrappers around @slot. Use names as suffixes such as animation:fade-in@motion-safe. Unlike @mode, a custom variant does not define where token variables are declared.

A reusable condition
Source
@custom-variant motion-safe {  @media (prefers-reduced-motion: no-preference) {    @slot;  }}.notice {  @variant motion-safe {    transition: opacity .2s ease;  }}
Result
@media (prefers-reduced-motion:no-preference) {  .notice {    transition: opacity .2s  }}

For token authoring, see Theme Tokens. For mode behavior, see Variables and Modes. For custom variant strategy, see Conditional Queries.


© 2026 Aoyue Design LLC.MIT License
Trademark Policy