Skip to content

Variants

A variant is a recipe applied on top of any color. You define the recipes; the library knows how to render each ingredient.

variants: {
solid: { background: 'fill', border: 'color', text: 'on' },
soft: { background: 'tint', border: 'none', text: 'color' },
outline: { background: 'none', border: 'color', text: 'color' },
ghost: { background: 'none', border: 'none', text: 'color' },
},
solidbadge
softbadge
outlinebadge
ghostbadge
Field Value Result
background fill the color itself; hover and active mix in the foreground
tint a translucent wash of the color
none transparent; hover shows a light tint
border color the color
neutral the neutral border color
none no visible border (the space is kept, so heights don’t change)
text on the color’s foreground
color the color’s text shade: the color itself, darkened or lightened only when it’s too faint to read
neutral the default text color

Any combination works. A “link” style is { background: 'none', border: 'none', text: 'color' }; a neutral outlined button is { background: 'none', border: 'neutral', text: 'neutral' }.

Button, IconButton, SplitButton, Badge, Alert, Avatar, AvatarGroup, Label, DatePicker, ToggleGroup and Pagination take a variant prop. They use the shared recipes unless you configure their own map. ButtonGroup inherits Button recipes.

  • defaults.variant: the variant of buttons and of a selected ToggleGroup item.
  • defaults.softVariant: the variant of low-emphasis components: Badge, Alert, and unselected ToggleGroup items.

Both must be keys of variants.

Set components.<Name>.variants to give a component its own recipe keys. This map replaces the shared group for that component’s variant prop. Other components continue using shared variants.

import { defineConfig } from '@yarcl/react/define';
import defaults from '@yarcl/react/defaults';
export default defineConfig({
...defaults,
components: {
Button: {
variants: {
action: { background: 'fill', border: 'color', text: 'on' },
link: { background: 'none', border: 'none', text: 'color' },
},
variant: 'action',
},
Badge: {
variants: {
status: { background: 'tint', border: 'none', text: 'color' },
},
variant: 'status',
},
},
});
<Button variant="action">Save changes</Button>
<Button variant="link">Learn more</Button>
<Badge variant="status">Approved</Badge>
<Alert variant="soft" title="Shared recipes still work" />
// Type errors: these keys belong to other groups.
<Button variant="status" />
<Badge variant="action" />
<Button variant="solid" />

Autocomplete suggests exactly the keys in that component’s map. Use ComponentVariant<'Button'> from @yarcl/react when typing your own wrapper. Variant continues to mean the shared group’s keys.

The ingredients are the same as shared recipes. To define CSS properties, custom slots, or variant axes such as emphasis and density, use component extensions.

A local map must have at least one entry. Keys cannot contain whitespace.

Set components.<Name>.variant when its map does not contain the inherited default key. You may omit it when that key is present. This is checked at compile time:

  • Button, IconButton, SplitButton and DatePicker inherit defaults.variant.
  • Badge, Alert, Avatar, AvatarGroup, ToggleGroup and Pagination inherit defaults.softVariant.
  • ToggleGroup and Pagination also inherit defaults.variant for selected items. Set their selectedVariant when the local map omits that key.
  • Label stays plain until a variant is provided through props or its component defaults.

Component defaults and explicit props must reference their own map’s keys. Without a local map, they must reference shared keys.

ButtonGroup accepts Button variant keys and passes the resolved recipe to its Button and IconButton children. An explicit child variant wins over the group, and is checked against that child’s own keys.

ToggleGroup and Pagination use their own maps for the buttons they render, including selected variants. They do not require those keys to exist in components.Button.variants or components.IconButton.variants.

AvatarGroup passes its recipe to avatars without an explicit variant. Explicit Avatar variants use the Avatar map. When the group has neither its own map nor a variant default, it inherits Avatar’s default recipe.

Shared keys generate yarcl-variant-{key}. Local keys generate yarcl-{Component}-variant-{key}, for example yarcl-Button-variant-action. Every key generates one class. CSS does not generate a separate rule for every color and size combination. Component namespaces keep identical key names independent, including names that resemble a shared key.

The design reference lists shared and component-specific recipes separately. Consumer overrides work through the same CSS cascade layers as other styles.

applyTheme updates the maps and defaults at runtime. Keep the variant keys used by your app when defining a replacement theme. Omitting a component map switches that component back to shared recipes, so the shared group must contain any explicit keys still used by its props.