Skip to content
Sveltier
Mode
Core

Shared props

Every component that has a variant, size, density, colour or rounding takes the same prop, with the same values and the same meaning.

The vocabulary

  • variant: elevated raises the colour as text on a surface with the theme's shadow, flat fills with the colour, tonal tints with it, outlined draws it as text and border, text as text only, and plain is text with no hover or press wash.
  • size: xs to xl. Each step is half a step of φ in height and a quarter step in text (Design scale).
  • density: compact, default or comfortable moves heights and paddings a quarter step of φ, never the text.
  • color: an intent (primary, success, warning, error, info, up, down), neutral, or a custom colour you register. Any other value is a type error.
  • rounded: true keeps the component's own radius, false or none squares it, sm–xl pick a theme radius and full makes a pill in every theme.

Set them once for a subtree with Defaults. Every value follows the active theme, so switch the theme or pack in the top bar and the preview below restyles.

Preview

Size
Density
Rounded
Variantprimarysuccesswarningerrorinfoupdownneutral
elevatedPayPayPayPayPayPayPayPay
flatPayPayPayPayPayPayPayPay
tonalPayPayPayPayPayPayPayPay
outlinedPayPayPayPayPayPayPayPay
textPayPayPayPayPayPayPayPay
plainPayPayPayPayPayPayPayPay

How it works

Each prop becomes a class, and each class only sets custom properties. The component decides where they apply, so one meaning works for a filled button, an outlined field and a tinted chip.

PropSets
color--sv-color,--sv-on-color
variant--sv-variant-bg,--sv-variant-fg,--sv-variant-border
size--sv-size-height,--sv-size-text
density--sv-density
rounded--sv-rounded

Hover and press mix --sv-variant-fg over --sv-variant-bg by --sv-state-hover (8%) and --sv-state-press (13%). The classes live in the sv.base layer, so a component can refine a value and your own unlayered CSS always wins.

Custom colours

Add the colour to your themes with defineTheme, then register its name. The theme stylesheet adds its sv-color-brand class, so it works like an intent, server-rendered and without inline styles.

themes.ts and app.d.ts
// themes.ts: add the colour to every theme you register
import { defineTheme, monolithDark, monolithLight } from 'sveltier';

export const themes = {
  'brand-light': defineTheme({ colors: { brand: 'oklch(0.55 0.15 300)' } }, monolithLight),
  'brand-dark': defineTheme({ colors: { brand: 'oklch(0.75 0.12 300)' } }, monolithDark)
};

// app.d.ts: make it a valid `color`
declare module 'sveltier' {
  interface CustomColors {
    brand: true;
  }
}

Your own components

sharedClasses is public, so your components can join the same system. Pass every shared prop the component has, defaults included: the variables inherit, and a missing class would let a nested component pick up its parent's value. For the same reason, only read the variables of props your component has.

app.d.ts
// app.d.ts
import type { Color, Size, Variant } from 'sveltier';

declare module 'sveltier' {
  interface ComponentDefaults {
    Pill: { variant: Variant; size: Size; color: Color };
  }
}
Pill.svelte
<script lang="ts">
  import {
    sharedClasses,
    useDefaults,
    type Color,
    type ComponentDefaults,
    type Size,
    type Variant
  } from 'sveltier';

  interface Props {
    label: string;
    variant?: Variant;
    size?: Size;
    color?: Color;
  }

  let { label, variant, size, color }: Props = $props();

  const resolve = useDefaults<ComponentDefaults['Pill']>('Pill', {
    variant: 'tonal',
    size: 'sm',
    color: 'neutral'
  });
  // Every shared prop the component has, defaults included.
  const p = $derived(resolve({ variant, size, color }));
</script>

<span class={['pill', sharedClasses(p)]}>{label}</span>

<style>
  .pill {
    display: inline-grid;
    place-items: center;
    block-size: var(--sv-size-height);
    padding-inline: calc(var(--sv-size-height) * 0.382);
    border: var(--sv-hairline) solid var(--sv-variant-border);
    border-radius: var(--sv-radius-full);
    background: var(--sv-variant-bg);
    color: var(--sv-variant-fg);
    font-size: var(--sv-size-text);
  }
</style>

See sharedClasses for the full API.