After declaring a signal, connect it to the page with bind and data- attributes. labb forwards Datastar’s attributes to its components. The examples on this page run in the browser without a request to Django.
This example binds an input, reads a signal with data-text, changes it with data-on:click, and responds with data-show.
Hello,
<c-lbr.signals $open="false" $name="" />
<div class="flex flex-col gap-4 w-full md:w-96">
<c-lb.input placeholder="Type your name" bind="$name" />
<p class="text-sm">
Hello, <span class="font-semibold" data-text="$name || 'stranger'"></span>
</p>
<c-lb.button btnStyle="soft" data-on:click="$open = !$open">
<span data-text="$open ? 'Hide details' : 'Show details'"></span>
</c-lb.button>
<c-lb.alert variant="info" alertStyle="soft" data-show="$open">
<span>These details are shown and hidden entirely in the browser.</span>
</c-lb.alert>
</div>
Bind an input
The bind prop keeps a signal in sync with what the user types or selects.
<c-lbr.signals $filters.q="" />
<c-lb.input type="search" bind="$filters.q" placeholder="Search" />
filters.q now holds the search text. bind works with input, textarea, select, checkbox, toggle, and range. When you use a typed schema, bind through the field descriptor.
<c-lb.input type="search" :bind=signals.fields.q />
Responding to events
Use data-on:<event> for a short expression that runs on an event. Read and update signals with $.
<c-lbr.signals $open="false" />
<c-lb.button data-on:click="$open = !$open">Toggle</c-lb.button>
<div data-show="$open">Now you can see me.</div>
Inside a data-on expression, the event is evt and the element is el. Write both without $, which is reserved for signals.
Add a timing modifier with __.
<c-lb.input data-on:input__debounce.300ms="..." />
<div data-on:mousemove__throttle.50ms="$mx = evt.clientX"></div>
The data- attributes
These attributes cover most local interface changes. They work on any element after a c-lbr. component or reactive $ prop loads the runtime.
| Attribute | Does |
|---|---|
data-show="$open" |
Shows or hides the element. |
data-text="$label" |
Sets the element's text content. |
data-class="{'active': $open}" |
Toggles classes. A key may hold several space-separated classes. |
data-attr:href="$url" |
Sets any attribute reactively. data-attr:style, data-attr:disabled, and so on. |
Use them for local toggles, tabs, and dropdowns. Use a server action when Django needs to own the change.
The search box, step two
Continuing the signals example, the input now binds to filters.q, a handler sets status, and Clear appears only when needed.
status = ""
<c-lbr.signals $filters.q="" $status="idle" />
<div class="flex flex-col gap-3 w-full max-w-sm">
<c-lb.input
type="search"
bind="$filters.q"
placeholder="Search customers"
data-on:input="$status = $filters.q ? 'searching' : 'idle'"
/>
<div class="rounded-lg bg-base-200/50 p-3 font-mono text-xs">
filters.q = "<span data-text="$filters.q"></span>"<br>
status = "<span data-text="$status"></span>"
</div>
<c-lb.button
btnStyle="ghost"
size="sm"
class="self-start"
data-show="$filters.q"
data-on:click="$filters.q = ''; $status = 'idle'"
>Clear</c-lb.button>
</div>
The example still runs entirely in the browser. Continue to Reactive props to let the signal drive the result badge.