Playground
A range control with a chunky pixel thumb. It wraps a native <input type="range">, so keyboard, touch and screen readers work out of the box. It exposes a numeric value property for data-bind.
Examples
Basic
<div style="display: grid; gap: 20px; inline-size: min(100%, 22rem)">
<sb-slider label="Thrust" value="72" unit="%"></sb-slider>
<sb-slider label="Heading" min="-180" max="180" value="30" unit="°" ticks></sb-slider>
<sb-slider label="Precision" min="0" max="1" step="0.01" value="0.5"></sb-slider>
</div>
Steer anything with signals
Declare a signal, bind the slider to it, and drive other elements' attributes with data-attr. Nothing goes to the server: signals that start with _ stay in the browser.
<div data-signals:_size="48" style="display: grid; gap: 16px; inline-size: min(100%, 22rem)">
<sb-slider label="Size" min="16" max="96" unit="px" data-bind:_size__prop.value></sb-slider>
<img src="/art/info.svg" alt="" data-attr:width="$_size" data-attr:height="$_size" style="image-rendering: pixelated">
</div>
When the driven element is a component inside a server-rendered region, add data-preserve-attr for those attributes. Then a server morph won't reset them:
<sb-gauge data-attr:value="$_fuel" data-preserve-attr="value"></sb-gauge>
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 native range input provides the role, value and keyboard support (arrow keys, Page Up/Down, Home/End). Give it a label; without one it is announced as "Value".
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-slider label="Thrust" value="72" unit="%" style="inline-size: 13rem"></sb-slider>
<!-- 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/slider@4ac6f4cdcb74/slider.js" integrity="sha384-fp/3R4nzxsvYNp3IIkoILLGMBdeliQgjGqwbRGo2FubjC39H2QymE7l4ek1pcQUG"></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.
| File | Original | gzip | brotli |
|---|---|---|---|
slider.js | 7.9 kB | 3.1 kB | 2.6 kB |
API reference
Props
| Attribute | Type | Default | Description |
|---|---|---|---|
value | number | 0 | The value. A new value from the server replaces it; the live value is the value property. |
min | number | 0 | Minimum. |
max | number | 100 | Maximum. |
step | number | 1 | Step size (0 for continuous). |
label | string | "" | Visible label. |
unit | string | "" | Suffix after the shown value, e.g. "°" or "%". |
show-value | boolean | true | Show the current value next to the label. |
ticks | boolean | false | Show min and max below the track. |
disabled | boolean | false | Disable interaction. |
confirm | boolean | false | Server-confirmed value: :state(pending) while the local value differs from the server's value attribute (see revert()). |
name | string | "" | Name reported in sb-change (e.g. the field of a command). |
Events
| Name | Description |
|---|---|
input | While dragging (native, re-targeted to the host). |
change | When the value is committed. |
sb-change | When the value is committed. detail: { name, value }: ready for a command. |