General

ThemeModeButton

A button that toggles between light and dark mode. Keep ThemeMode in your root layout: the button can flip the mode on its own, but ThemeMode is what applies the saved choice when a page loads.

Playground

Basic Usage

Drop in anywhere below ThemeMode.

<script lang="ts">
  import { ThemeModeButton } from 'sv5ui';
</script>

<ThemeModeButton />

Variants

ghost
outline
soft
subtle
solid
<ThemeModeButton variant="ghost" />
<ThemeModeButton variant="outline" />
<ThemeModeButton variant="soft" />
<ThemeModeButton variant="subtle" />
<ThemeModeButton variant="solid" />

Sizes

xs
sm
md
lg
xl
<ThemeModeButton size="xs" />
<ThemeModeButton size="sm" />
<ThemeModeButton size="md" />
<ThemeModeButton size="lg" />
<ThemeModeButton size="xl" />

Colors

<ThemeModeButton color="surface" />
<ThemeModeButton color="primary" />
<ThemeModeButton color="secondary" />
<ThemeModeButton color="success" />
<ThemeModeButton color="warning" />
<ThemeModeButton color="error" />
<ThemeModeButton color="info" />

Accessibility

The button is named Toggle theme, which describes what it does in either mode. Naming it after the target mode reads worse than it sounds: the name changes under the reader's finger the moment they press it, and it is wrong for the brief moment between the press and the class landing on <html>.

Both icons are in the DOM at all times and hidden dark:block decides which one shows. That is what keeps the server markup and the first client render identical, so nothing flickers or sticks on reload.

Custom Icons

Override the default sun/moon icons. Both are rendered; CSS shows one.

<!-- Custom icon set -->
<ThemeModeButton
  lightIcon="lucide:sunrise"
  darkIcon="lucide:sunset"
/>

<!-- Different icon collections -->
<ThemeModeButton
  lightIcon="mdi:white-balance-sunny"
  darkIcon="mdi:weather-night"
/>

Custom Content

Use children snippet with isDark for fully custom content.

<ThemeModeButton>
  {#snippet children({ isDark })}
    {isDark ? '🌙' : '☀️'}
  {/snippet}
</ThemeModeButton>

Click Handler

Pass onclick to run your own code on a press, for analytics or to save the choice to an account. It runs before the toggle. To stop the toggle, call event.preventDefault() in the handler.

Pressed 0 times
Blocked 0 times
<script lang="ts">
  import { ThemeModeButton, Switch } from 'sv5ui';

  let clicks = $state(0);
  let locked = $state(true);
</script>

<!-- Runs first, then the mode toggles -->
<ThemeModeButton onclick={() => (clicks += 1)} />

<!-- preventDefault() cancels the toggle -->
<ThemeModeButton
  onclick={(event) => {
    if (locked) event.preventDefault();
  }}
/>
<Switch bind:checked={locked} label="Lock the theme" />

Loading

loading swaps the mode icons for a spinner and disables the button, for the moment a choice is being saved somewhere.

<ThemeModeButton loading />
<ThemeModeButton loading variant="outline" />
<ThemeModeButton loading variant="solid" color="primary" />

Styled Examples

Navbar
Accent
Minimal
<!-- Outline style for navbars -->
<ThemeModeButton variant="outline" color="surface" />

<!-- Solid accent button -->
<ThemeModeButton variant="solid" color="primary" />

<!-- Subtle minimal style -->
<ThemeModeButton variant="subtle" color="surface" size="sm" />

UI Slots

SlotDescription
baseRoot button element - controls layout, colors, transitions
iconIcon element - controls icon sizing and shrink behavior

Snippets

SnippetPropsDescription
childrenisDark: booleanCustom content replacing default icon, receives current theme state

Props

PropTypeDefault
variant'solid'|'outline'|'soft'|'subtle'|'ghost'|'link''ghost'
colorColorType'surface'
size'xs'|'sm'|'md'|'lg'|'xl''md'
lightIconstring'lucide:sun'
darkIconstring'lucide:moon'
loadingbooleanfalse
onclick(event: MouseEvent) => void-
disabledbooleanfalse
squarebooleantrue
blockbooleanfalse
classstring-
uiRecord<Slot, Class>-