See Datastar in action with this reactive todo app. Add tasks, toggle completion, and filter - all with real-time UI updates.
A lightweight (14.3 KiB) JavaScript library that adds reactivity to HTML using data-* attributes. Use with any backend language and Server-Sent Events for real-time UI updates.
Add reactivity directly to HTML with data-* attributes.
State is managed through reactive signals that automatically track and propagate changes throughout your UI.
Embrace the web's natural architecture. Keep logic on the server and your frontend lightweight and focused.
ds_bind(signal_name)
Creates a two-way connection between form elements and signals. When users interact with the element, the signal updates automatically.
Input(ds_bind('input1'), ...)
ds_text(expr)
Sets an element's text content based on signal values using JavaScript expressions. Great for displaying dynamic output that updates automatically when signals change.
$input
$input.toUpperCase()
$input ? $input : 'Nothing entered'
'Length: ' + $input.length
Span(ds_text('$input.toUpperCase()'))
ds_computed(name=expr, ...)
Creates new read-only signals derived from reactive expressions. These computed values update automatically when their dependencies change.
$input.length
$input.repeat(2)
$input ? $input.toUpperCase() : 'Nothing entered'
Div(ds_computed(doubled='$input.repeat(2)'))
ds_show(when=expr)
Conditionally shows or hides elements based on reactive expressions. Elements are only visible when the expression evaluates to true.
$input != ''
!$input
$count > 10 && $isAdmin
ds_show(when="$input != ''")
ds_show("$input != ''")
Button(ds_show(when='$input != ""'), 'Save')
ds_classes(**expressions)
Conditionally applies CSS classes based on reactive expressions. Classes are added when the expression evaluates to true and removed when false.
ds_classes(hidden="$input == ''")
ds_classes(text_primary="$input.length > 0", font_bold="$input.length > 3")
ds_classes(bg_error="$isInvalid", text_success="$isValid")
Div(ds_classes(text_primary="$input.length > 0"))
ds_attrs(**expressions)
Reactively sets HTML attributes based on signal values. Attributes are updated automatically when the expressions evaluate to new values.
ds_attrs(disabled="$input == ''")
ds_attrs(disabled="!['red', 'blue'].includes($input)", title="$input ? 'Submit ' + $input : 'Enter a valid color'")
ds_attrs(style="'color: ' + ($isError ? 'red' : 'green')")
ds_attrs(aria_expanded="$isOpen", aria_label="$buttonLabel")
Button(ds_attrs(disabled="$isEmpty"), "Save")
ds_signals(**signal_values)
Initializes reactive signals that can be accessed throughout your application. Signals are the foundation of Datastar's reactivity system.
ds_signals(count="0")
- Numbers don't need quotes in JavaScript ds_signals(name="'Anonymous'")
- Strings require quotes in JavaScript (inner quotes) ds_signals(isAdmin="false")
- JavaScript booleans are lowercase ds_signals(count="0", name="'User'", isAdmin="false")
- Define several at once ds_signals(user__name="'Anonymous'")
- Double underscore becomes dot notation ds_signals(user=json_dumps({"name": "", "email": ""}))
- For complex nested data Div(ds_signals(count="0", name="'User'"))
ds_on(**event_handlers)
Attaches event listeners to elements that execute JavaScript expressions when triggered. This enables interactive UI without writing custom JavaScript functions.
ds_on(click="$count++")
ds_on(click="$count = 0; $message = 'Reset'")
ds_on(input="$value = evt.target.value")
ds_on(keydown="if(evt.key === 'Enter') $submit = true")
ds_on(click="@post('/api/data')")
The special evt
variable gives access to the browser's native event object, allowing you to access properties like evt.target
, evt.key
, etc.
Button(ds_on(click="$count++"), "Increment")
ds_signals, ds_computed, ds_on, ds_show, ds_text
This example demonstrates a simple interactive quiz using Datastar's client-side reactivity features.
ds_signals
for state management ds_computed
for answer validation ds_on
for user interaction ds_show
for dynamic feedback ds_text
for displaying values While the initial HTML is served from a route, all quiz interactions happen entirely in the browser without additional server requests. This makes it simple to implement but limits it to using hardcoded questions.
Button(ds_on(click="$response = prompt('Answer:')"), "Answer")
@get, signal_update, fragment_update
Building on the client-side quiz, this example demonstrates how to enhance the experience with server-side functionality using Server-Sent Events (SSE).
@get
directive for dynamic content signal_update
fragment_update
Unlike the previous example where all interaction happens in the browser, this quiz makes additional server requests during use to fetch new questions and answers, demonstrating how Datastar bridges client and server functionality.
Button(ds_on(click="@get('/actions/quiz')"), "Fetch Question")
@sse, signal_update, fragment_update
Datastar provides a powerful way to create server routes that can send real-time updates to the client using Server-Sent Events (SSE).
@sse
decorator marks a route as an SSE endpoint fragment_update
replaces or modifies HTML elements signal_update
changes signal values without reloading the page @rt("/your/path")
@sse
decorator to enable streaming yield
to send updates to the client @get
, @post
, etc. directives @rt("/api/data") @sse async def handler(): yield signal_update(...)
ds_indicator(signal_name)
ds_indicator("signal_name")
to create a signal that tracks the loading state true
during the request and false
when complete ds_show
or ds_classes
to create responsive loading states Button("Load Data", ds_on(click="@get('/api/data')"), ds_indicator("loading"))
@setAll(prefix, value) / @toggleAll(prefix)
@setAll(prefix, value)
sets all signals that match the prefix to the specified value @toggleAll(prefix)
toggles the boolean value of all signals that match the prefix Button("Check All", ds_on(click="@setAll('checkboxes.', true)"))
signal_update(), fragment_update()
yield fragment_update(status_component, "#container", "inner")
Get building! Or explore the standalone Todo app some more.