# Theme Toggle

<FrameworkCodeSwitcher>
  <div slot="astro">
```astro
---
import { ThemeToggle } from "@/components/starwind/theme-toggle";
---

<ThemeToggle ariaLabel="Toggle theme" />
```
  </div>
  <div slot="react">
```tsx
import { ThemeToggle } from "@/components/starwind/theme-toggle";

export function Example() {
  return (
    <>
      <ThemeToggle ariaLabel="Toggle theme" />
    </>
  );
}
```
  </div>
</FrameworkCodeSwitcher>

> **Info:** Theme Toggle now uses the shared theme controller from `@starwind-ui/astro/theme`. Controls with
the same sync group stay aligned across Astro navigation and system-theme changes.

## Installation

```bash
npx starwind@latest add theme-toggle
```

## Usage

### Preventing a theme flash

Render `ThemeInitScript` in your document head. It applies the persisted or system theme before
the page becomes visible.

```astro
<html>
  <head>
    <ThemeInitScript />
  </head>
  <body>
    <slot />
  </body>
</html>
```

### Custom icons

```astro
---
import Heart from "@tabler/icons/outline/heart.svg";
import Star from "@tabler/icons/outline/star.svg";
import { ThemeToggle } from "@/components/starwind/theme-toggle";
---

<ThemeToggle ariaLabel="Toggle theme with custom icons">
  <Heart
    slot="light-icon"
    class="hidden size-5 group-data-[state=off]:data-ready:block"
    data-theme-icon
  />
  <Star
    slot="dark-icon"
    class="hidden size-5 group-data-[state=on]:data-ready:block"
    data-theme-icon
  />
</ThemeToggle>
```

> **Info:** Custom icon visibility follows the Runtime-owned `data-state` and `data-ready` attributes. Keep
`data-theme-icon` on each icon so the controller can synchronize it.

## Framework Availability
Theme Toggle is available for Astro and React.
Astro available; React available
| Framework | Status | Notes |
| --- | --- | --- |
| Astro | available | - |
| React | available | - |
## API Reference
### ThemeToggle
| Prop | Type | Required | Default | Kind | Description |
| --- | --- | --- | --- | --- | --- |
| `ariaLabel` | `string` | No | `"Toggle theme"` | Wrapper prop | Provides an accessible label when visible text is not available. |
| `defaultPressed` | `boolean` | No | - | Wrapper prop | Sets the initial pressed state when the control is uncontrolled. |
| `disabled` | `boolean` | No | `false` | Wrapper prop | Disables interaction with the component. |
| `pressed` | `boolean` | No | - | Wrapper prop | Controls the pressed state. |
| `size` | `"sm" \| "md" \| "lg"` | No | `"md"` | Styled variant | Selects the component's visual size. |
| `syncGroup` | `string` | No | `"starwind-theme"` | Wrapper prop | Synchronizes pressed state across Theme Toggles in the same named group. |
| `value` | `string` | No | - | Wrapper prop | Controls or identifies the component value. |
| `variant` | `"default" \| "outline"` | No | `"outline"` | Styled variant | Selects the component's visual variant. |
- Inherits button attributes. Omits `aria-pressed`, `defaultPressed`, `disabled`, `onChange`, `type`, and `value`.

## Changelog

### v2.0.0

- Added contract-generated Astro and React implementations and replaced page-local storage logic with the shared Runtime theme controller and `ThemeInitScript`.
- See the [Runtime theme reference](/docs/runtime/#theme) for the shared theme behavior and helpers.