Button

A versatile button component with Datastar interactions.

zweiundeins <sb-button> button action link cta Since 2026-09-21 1.5 kB0Open in playground Edit on GitHub

Playground

Blast off

Buttons start things. sb-button comes in five variants, three sizes, and renders a real <a> when given an href. Clicks bubble out of the shadow root, so any Datastar data-on:click just works.

Examples

Variants

Primary Outline Ghost Abort Blast off
<sb-button>Primary</sb-button>
<sb-button variant="outline">Outline</sb-button>
<sb-button variant="ghost">Ghost</sb-button>
<sb-button variant="danger">Abort</sb-button>
<sb-button variant="pixel" caret>Blast off</sb-button>

Sizes

Small Medium Large
<sb-button size="sm">Small</sb-button>
<sb-button size="md">Medium</sb-button>
<sb-button size="lg">Large</sb-button>

With Datastar

Local signals start with an underscore, so they stay in the browser and are never sent to the server.

Launches: Reset
<div data-signals:_count="0">
  <sb-button data-on:click="$_count++">Launches: <span data-text="$_count"></span></sb-button>
  <sb-button variant="ghost" data-on:click="$_count = 0" data-attr:disabled="$_count === 0">Reset</sb-button>
</div>

Talking to the backend works the same way: data-on:click="@post('/launch')".

Read the Datastar docs
<sb-button href="https://data-star.dev" variant="outline" caret>Read the Datastar docs</sb-button>

Accessibility

A native <button> (or <a>) inside the shadow root does the work: keyboard focus, Enter and Space, and screen reader semantics. Disabled buttons are removed from the tab order.

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-button variant="pixel" size="lg" caret>Blast off</sb-button>

<!-- 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/button@c2cfadcfa32e/button.js" integrity="sha384-5npQOrbSGCTtdgj9bnJ29fsJCbLAFkc+rCVnwEJnlm3uBuw7ew8rQVzYeRu+Dt24"></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
button.js 4.4 kB1.7 kB1.5 kB

API reference

Props

AttributeTypeDefaultDescription
variant"primary" | "outline" | "ghost" | "pixel" | "danger""primary"Visual style.
size"sm" | "md" | "lg""md"Height and padding.
hrefstring""Render as a link to this URL.
caretbooleanfalseShow a trailing chevron.
disabledbooleanfalseDisable interaction.

Slots

NameDescription
defaultThe label.
prefixAn icon before the label.
suffixAn icon after the label.