Get started

Theming

Components read CSS variables. Change tokens for a system-wide look, or override a single component with classes and selectors.

Where tokens live

Package installs use @mielui/svelte/ui.css. CLI installs use src/lib/mielui/ui.css. Both define the same color, typography, radius, and motion tokens.

Theme Studio

Theme Studio lets you start from a preset and adjust colors, fonts, spacing, motion, and surface effects. Open All color tokens at the end of the Color tab to edit individual color tokens.

Studio saves your draft locally when browser storage is available. If storage is blocked or full, download the theme JSON to preserve your changes.

Choose Export theme, open the CLI tab, download mielui-theme.json into your project root, and run the command for a new or existing Mielui setup. The JSON includes both color modes and all Studio overrides. New setups get styles.css, which imports ui.css followed by theme.css. Load that stylesheet in your root layout. Fonts must also be loaded by your app.

pnpm dlx @mielui/svelte init --preset ./mielui-theme.json

For an existing setup, run the command below. It replaces theme.css. Built-in preset slugs, such as default, can be used in place of the JSON path.

pnpm dlx @mielui/svelte add theme ./mielui-theme.json

Global glass surfaces

Surfaces are solid by default. Turn glass on under Surface in Studio, or set --mielui-surface: glass on :root. Components with surface support inherit that choice when the prop is omitted. Set surface="solid" or surface="glass" on one component to override the theme. Put the variable on :root so portaled menus and dialogs inherit it too.

:root {
  --mielui-surface: glass;
}

The global setting uses CSS style queries. Browsers without style-query support retain solid surfaces. Explicit surface="glass" still works with backdrop-filter support. Reduced transparency keeps an opaque background and removes blur.

The glass backdrop in the Studio preview options adds color behind the preview. It is a viewing aid and is not included in your exported theme.

Override tokens

Set values in your app CSS after importing Mielui's sheet. Light defaults go in @theme. Dark values go under .dark.

@theme {
  --color-primary: #155eef;
  --color-background: #fcfcfd;
  --color-foreground: #101828;
  --radius-control: 9999px;
  --font-sans: 'DM Sans', sans-serif;
}

.dark {
  --color-background: #0d1118;
  --color-foreground: #f5f7fb;
  --color-primary: #7aa2ff;
}

The focus ring, the info status color, and the accent tint are mixed from --color-primary, so one value rebrands all of them. Set --color-on-primary when the text on filled buttons needs a different color.

Useful public tokens

  • Color --color-background --color-card --color-panel --color-secondary --color-foreground --color-foreground-muted --color-primary --color-on-primary --color-button-foreground --color-border --color-input --color-ring
  • Status text --mielui-success-text --mielui-warning-text --mielui-error-text --mielui-info-text
  • Controls --size-control-sm --size-control-md --size-control-lg --size-icon-md --mielui-control-border --focus-ring
  • Type --font-sans --font-mono --font-header --font-size-header --font-weight-body --font-weight-label --font-weight-button
  • Radius and density --radius-sm --radius-md --radius-lg --radius-xl --radius-2xl --radius-control --mielui-space-unit
  • Motion --motion-duration-hover --motion-duration-menu --motion-duration-panel --motion-duration-sheet
  • Elevation --elevation-1 --elevation-float --elevation-control --elevation-control-edge --elevation-modal

Controls use three heights. Icon buttons match the medium height. --focus-ring is a 3px ring at half the primary color, and it composes with each control's existing edge. The default radius scale is 8, 10, 14, and 18 pixels from small to extra large. Plates use --radius-2xl, 26 pixels, and everything pressable uses --radius-control: 4 pixels in the sharp scale, 12 in the default scale, and a pill in the rounded scale.

Use the status text tokens for success, warning, error, and info copy on tinted backgrounds and cards. They reach 4.5:1 contrast, while the raw status colors remain for fills, icons, and charts.

Built-in presets

Mielui ships 18 built-in presets: default, magic, bitsy, open, functional, daydream, honey, forest, ink, ocean, console, ember, lilac, profitable, raven, clawd, inspiration, and government. Preview them live on the themes page, where you can copy each preset's CSS or JSON.

With the CLI, install a preset into theme.css:

pnpm dlx @mielui/svelte add theme open

Import it after ui.css to apply its overrides:

@import './lib/mielui/ui.css';
@import './lib/mielui/theme.css';

mielui list shows available built-in theme slugs.

Dark mode

Toggle a .dark class on <html>. Components do not manage the class for you.

Theme JSON

Theme JSON version 4 is the format shared by Studio and the CLI. Export it from Studio to preserve both color modes and your overrides.

  • Base fields version, slug, name, description, brand, neutral, radius, density, motion, fontSans, fontMono, and fontHeader are required. publisher is optional.
  • foundation light and dark hold each mode's base, border, background, secondary, foreground, foregroundMuted, onPrimary, and buttonForeground colors.
  • typography headerSize, headerWeight, and roleWeights for body, label, button, badge, and description text.
  • tokens shared, light, and dark hold raw token overrides keyed by custom property, including per-mode values for --color-primary.
  • chrome borders, edgeHighlight, surfaceShadows, controlShadows, dialogShadows, travelingHighlight, primaryStroke, and interactiveCursor. Turning off travelingHighlight keeps the selected fill and removes its movement.

Set motion: "none" to disable animations, including dialogs, menus, and the traveling highlight. Edge highlight strength ranges from 0 to 1.

Class overrides

Styled components accept class. Use Tailwind utilities or your own classes for one-off tweaks.

<Button class="w-full rounded-2xl">Continue</Button>

Component selectors

Components render data-ui, and often data-variant or data-size. Scope CSS to a family without forking files.

[data-ui='button'][data-variant='primary'] {
  border-radius: var(--radius-md);
}

[data-ui='badge'][data-variant='secondary'] {
  text-transform: uppercase;
}

Edit the source

With the CLI path, files live under src/lib/mielui/components/<name>/. Edit them when you need behavior changes, not just style.

# after: pnpm dlx @mielui/svelte add button
src/lib/mielui/components/button/
├── button.svelte
└── index.ts

Borders

Framed surfaces are a white frame holding a recessed inset in the page background. Set chrome.borders to "single" so the inset meets the border of the frame, or "double" for a gutter between the two. The default is "single". Studio exposes this choice as Borders on the Surface tab.

const theme = {
    ...DEFAULT_THEME,
    chrome: { borders: 'single' as const }
};

const css = themeToCss(theme);

The setting covers inset layouts: dialogs, sheets, drawers, toasts, Notch, code blocks, diffs, inset tables, inset and panel cards, alerts, and composers. Inset variants keep their content padding and footer composition.

Menus, selects, comboboxes, popovers, hover cards, date-picker panels, and chart tooltips always use a single border, so a small floating panel never shows stacked edges. Glass, shadows, focus, and edge highlights remain independent of the setting.

Chart colors

Studio's Color → Chart colors controls edit --chart-1 through --chart-5 for the active light or dark theme. The defaults are pastel purple, pink, blue, green, and yellow. Cartesian charts, pie charts, gauges, heatmaps, and their demos use these tokens. Explicit series colors and semantic gauge tones still take precedence.

:root {
  --chart-1: #b8a1f2;
  --chart-2: #f49d9d;
  --chart-3: #8bc7f5;
  --chart-4: #8ed8b0;
  --chart-5: #f2d77d;
}

Inset strip position

In Theme Studio, Surface, then Inset strip, moves exposed chrome above or below its inset content. Studio exports --mielui-inset-position as top or bottom. Without that token, components keep their authored order.

Override it locally with class="[--mielui-inset-position:top]" when a header must stay above its content, as the installation command tabs do. Data tables keep filters above rows and pagination below them.

Edge highlights

Filled controls are flat by default: buttons, moving thumbs, and selected segments take one solid fill held by a hairline, with no gradient or inner light. Set chrome.edgeHighlight above 0 to light them all at once. It also scales the light edge on keycaps. The default is 0, the flat look; 0.33 is the original lit look and 1 is full strength. Text fields, selection triggers, and outline buttons carry no fill either way. Focus rings, borders, and drop shadows keep their existing colors and opacity. Shadow switches still take precedence.

The glow button variant stays lit in a flat theme. To light another control on its own, add the mielui-glow-lit class next to mielui-glow.

const theme = {
    ...DEFAULT_THEME,
    chrome: { edgeHighlight: 0.5 }
};

const css = themeToCss(theme);

Studio exposes Edge highlight on the Surface tab. It is off by default. Turning it on restores 30%, or the last strength used in that session, and you can adjust the strength while it is on. Preset JSON, copied CSS, saved drafts, and CLI theme imports preserve it.

A near-white primary button with dark text, common in dark app interfaces, is a theme choice rather than a variant. Apply the built-in Open preset, whose dark primary is near-white, or set the brand color yourself.

Next

Browse the Components to see these tokens on live examples.