Toggle

A switch component with smooth Datastar interactions.

zweiundeins <sb-toggle> switch checkbox boolean Since 2026-09-21 1.9 kB0Open in playground Edit on GitHub

Playground

An on/off switch with chunky pixel corners and stepped motion. It exposes a checked property and fires change, so Datastar can bind to it like a native checkbox.

Examples

Basic

<sb-toggle label="Warp drive"></sb-toggle>
<sb-toggle label="Shields" checked></sb-toggle>
<sb-toggle label="Self-destruct" disabled></sb-toggle>

Sizes

<sb-toggle size="sm" checked></sb-toggle>
<sb-toggle size="md" checked></sb-toggle>
<sb-toggle size="lg" checked></sb-toggle>

Two-way binding

Bind the checked property with data-bind and the __prop and __event modifiers.

<div data-signals:_thrusters="false">
  <sb-toggle label="Thrusters" data-bind:_thrusters__prop.checked__event.change></sb-toggle>
  <p data-text="$_thrusters ? 'Thrusters engaged' : 'Thrusters idle'"></p>
</div>

With commands

Give it a name, and it emits sb-change with { name, value } when a value is committed: ready to post as a command. With confirm, it sets :state(pending) until the server's re-rendered attribute matches, and revert() goes back to the server's value when a command is rejected. See Commands and components and the Showcase.

Accessibility

The switch is a <button role="switch"> with aria-checked, so it is focusable and toggles with Space and Enter. Give it a label. Without one it is announced as "Toggle".

Installation

Add Datastar with Rocket and the Starbase autoloader once per page, then use the tag. The autoloader imports each component the first time its tag appears, including tags added later by a Datastar morph.

<!-- Once per page: Datastar with Rocket, and the Starbase autoloader.
     It loads every <sb-…> component the first time its tag appears. -->
<script type="importmap">
  { "imports": { "datastar": "https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.4/bundles/datastar-rocket.js" } }
</script>
<script type="module" src="https://starbase.zweiundeins.gmbh/c/autoloader.js"></script>
<!-- Optional, no flash of undefined elements: class="sb-cloak" on <html>, and -->
<style>.sb-cloak :not(:defined) { visibility: hidden }</style>

<sb-toggle checked size="lg"></sb-toggle>

<!-- In production, pin today's catalog instead of the latest: the browser then
     refuses any file that changed. Add "integrity" to the import map above: the
     hashes from https://starbase.zweiundeins.gmbh/c/@0a1ad1bf98a4/importmap.json and Datastar's, below. -->
<!--
<script type="importmap">
  { "imports": { "datastar": "https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.4/bundles/datastar-rocket.js" },
    "integrity": { "https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.4/bundles/datastar-rocket.js": "sha384-vUxZojLrF1Ar3de5h7VINqhJXBgjyZS4U49pHvGa87kum6j5Xn6JRziuARNw5ELG", "…": "…from importmap.json" } }
</script>
<script type="module" src="https://starbase.zweiundeins.gmbh/c/@0a1ad1bf98a4/autoloader.js" integrity="sha384-IvSCUjEWPS+wwXunU+48x96KmyWDx/Y4LeCwCL8cWFqJ/zHmTsTOsSMrzTOcpW3D"></script>
-->

<!-- Or load just this component, pinned to this version: -->
<!-- <script type="module" src="https://starbase.zweiundeins.gmbh/c/toggle@cc22753fafc0/toggle.js" integrity="sha384-fHJvGNCtrikrmtXzRhjnA3xizooJKuFu9Lmz4iZGz8gJPcKk4avv7M1vXE4tivCu"></script> -->

Size

Each file compressed on its own, the way it is served (gzip -9, brotli -11). Datastar and Rocket are shared by every component and not counted.

FileOriginalgzipbrotli
toggle.js 5.5 kB2.3 kB1.9 kB

API reference

Props

AttributeTypeDefaultDescription
checkedbooleanfalseOn or off. A new state from the server wins (send checked="false" to switch it off); the live state is the checked property.
disabledbooleanfalseDisable interaction.
labelstring""Visible label next to the switch.
size"sm" | "md" | "lg""md"Size of the switch.
confirmbooleanfalseServer-confirmed value: :state(pending) while the local value differs from the server's value attribute (see revert()).
namestring""Name reported in sb-change (e.g. the field of a command).

Events

NameDescription
changeAfter the user flips the switch.
sb-changeSame moment. detail: { name, value, checked } (value is the checked state): ready for a command.