DataStar HTMX Quick Start - vicmay/DATASTAR GitHub Wiki
DATASTAR is a hypermedia framework that unifies the reactivity of Alpine.js (frontend) and htmx (backend) into a single, lightweight, extensible solution. It enables you to build reactive web applications using declarative HTML attributes and server-sent events (SSE), with the simplicity of server-side rendering and the power of a full-stack SPA framework.
- Website: data-star.dev
- GitHub: starfederation/datastar
- Current Version: v1.0.0-beta.11
- Getting Started
- Core Concepts
- Frontend Features
- Backend Integration
- Actions
- Advanced Examples
- DATASTAR vs HTMX: Detailed Comparison and Differentiation
- Best Practices
- Community & Resources
Via CDN:
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/[email protected]/bundles/datastar.js"></script>
Self-hosted:
<script type="module" src="/path/to/datastar.js"></script>
Via npm:
npm install @starfederation/datastar
- Signals: Reactive variables that track and propagate changes. Created via data attributes or backend events.
-
Declarative HTML: Use
data-*
attributes to bind state, events, and logic directly in your markup. - Server-Sent Events (SSE): Stream events from your backend to update the frontend in real time.
Signals are the foundation of reactivity in DATASTAR. They are special variables that automatically track and propagate changes throughout your application. When a signal's value changes, any part of your UI or logic that depends on that signal will automatically update to reflect the new value.
- Signals are reactive variables managed by DATASTAR.
- They are created and updated using
data-*
attributes in your HTML (such asdata-bind
,data-computed
, ordata-signals
). - When a signal changes, any DOM element or expression that references it will update automatically, without you having to write extra JavaScript.
- They allow you to build dynamic, interactive UIs declaratively, just by writing HTML.
- You don't need to manually update the DOM or keep track of state changes—DATASTAR does it for you.
- Signals can be updated from both the frontend (user input, events) and the backend (via Server-Sent Events).
<input data-bind="username" />
<div data-text="$username"></div>
- Here,
data-bind="username"
creates a signal calledusername
. - The
<div>
will always display the current value ofusername
. - If the user types in the input, the
<div>
updates automatically.
You can also create signals whose values depend on other signals:
<input data-bind="firstName" />
<input data-bind="lastName" />
<div data-computed-fullName="$firstName + ' ' + $lastName">
<span data-text="$fullName"></span>
</div>
-
fullName
is a computed signal that always reflects the combination offirstName
andlastName
. - If either input changes,
$fullName
and the displayed value update automatically.
- Signals are the reactive state in DATASTAR.
- They make your UI automatically update in response to changes, without manual DOM manipulation.
- You define and use them declaratively in your HTML.
Two-way data binding for input elements. Creates a signal bound to the element's value.
<input data-bind-input />
<!-- or -->
<input data-bind="input" />
- Access the value as
$input
in expressions.
Sets the text content of an element to a signal or expression.
<input data-bind-input />
<div data-text="$input">I will be replaced with the contents of the input signal</div>
<div data-text="$input.toUpperCase()">Uppercase: $input</div>
Creates a read-only signal based on a reactive expression.
<input data-bind-input />
<div data-computed-repeated="$input.repeat(2)">
<div data-text="$repeated"></div>
</div>
Conditionally shows or hides an element based on an expression.
<input data-bind-input />
<button data-show="$input != ''">Save</button>
Adds or removes classes based on expressions.
<input data-bind-input />
<button data-class-hidden="$input == ''">Save</button>
<!-- Multiple classes -->
<button data-class="{hidden: $input == '', 'font-bold': $input == 1}">Save</button>
Binds HTML attributes to expressions.
<input data-bind-input />
<button data-attr-disabled="$input == ''">Save</button>
<!-- Multiple attributes -->
<button data-attr="{disabled: $input == '', title: $input}">Save</button>
Defines or merges signals into the global set.
<div data-signals-input="1"></div>
<div data-signals-form.input="2"></div>
<div data-signals="{input: 1, form: {input: 2}}"></div>
Attaches event listeners and executes expressions.
<input data-bind-input />
<button data-on-click="$input = ''">Reset</button>
Sets a signal to true
while a request is in flight, otherwise false
.
<button data-on-click="@get('/actions/quiz')" data-indicator-fetching>Fetch a question</button>
<div data-class-loading="$fetching" class="indicator"></div>
DATASTAR uses Server-Sent Events (SSE) to stream updates from the backend. Official SDKs are available for Clojure, C#, Go, Haskell, Java, PHP, Python, Rust, Ruby, TypeScript, and Zig.
Example (Node.js/Express):
ServerSentEventGenerator.stream(req, res, (stream) => {
stream.mergeFragments('<div id="question">What do you put in a toaster?</div>');
stream.mergeSignals({response: '', answer: 'bread'});
});
Example (Clojure):
(require '[starfederation.datastar.clojure.api :as d*]
'[starfederation.datastar.clojure.adapter.http-kit :refer [->sse-response on-open]])
(defn handler [request]
(->sse-response request
{on-open
(fn [sse]
(d*/merge-fragment! sse "<div id=\"question\">What do you put in a toaster?</div>")
(d*/merge-signals! sse "{response: '', answer: 'bread'}"))}))
Example (C#):
using StarFederation.Datastar.DependencyInjection;
builder.Services.AddDatastar();
app.MapGet("/", async (IDatastarServerSentEventService sse) => {
await sse.MergeFragmentsAsync("<div id=\"question\">What do you put in a toaster?</div>");
await sse.MergeSignalsAsync("{response: '', answer: 'bread'}");
});
DATASTAR provides helper actions for use in data-*
attributes.
Sets the value of all matching signals.
<button data-on-click="@setAll('foo.*', $bar)"></button>
<!-- Example: Check all checkboxes -->
<input type="checkbox" data-bind-checkboxes.checkbox1 /> Checkbox 1
<input type="checkbox" data-bind-checkboxes.checkbox2 /> Checkbox 2
<input type="checkbox" data-bind-checkboxes.checkbox3 /> Checkbox 3
<button data-on-click="@setAll('checkboxes.*', true)">Check All</button>
Toggles the value of all matching signals.
<button data-on-click="@toggleAll('foo.*')"></button>
<!-- Example: Toggle all checkboxes -->
<input type="checkbox" data-bind-checkboxes.checkbox1 /> Checkbox 1
<input type="checkbox" data-bind-checkboxes.checkbox2 /> Checkbox 2
<input type="checkbox" data-bind-checkboxes.checkbox3 /> Checkbox 3
<button data-on-click="@toggleAll('checkboxes.*')">Toggle All</button>
<div id="contact_1">
<label>First Name: John</label>
<label>Last Name: Doe</label>
<label>Email: [email protected]</label>
<div>
<button data-on-click="@get('/examples/click_to_edit/contact/1/edit')">Edit</button>
<button data-on-click="@get('/examples/click_to_edit/contact/1/reset')">Reset</button>
</div>
</div>
Edit Form:
<div id="contact_1" data-signals="{id: 1, firstName: 'John', lastName: 'Doe', email: '[email protected]'}">
<div class="form-control">
<label>First Name</label>
<input type="text" data-bind="firstName" />
</div>
<div>
<label>Last Name</label>
<input type="text" data-bind="lastName" />
</div>
<div>
<label>Email</label>
<input type="text" data-bind="email" />
</div>
<div>
<button data-on-click="@put('/examples/click_to_edit/contact/1')">Save</button>
<button data-on-click="@get('/examples/click_to_edit/contact/1')">Cancel</button>
</div>
</div>
HTMX is a popular JavaScript library that allows you to access modern browser features directly from HTML, enabling you to make AJAX requests, handle server-sent events (SSE), and update parts of your web page without writing custom JavaScript. HTMX uses special hx-*
attributes in your HTML to declaratively specify how elements should interact with the server and update the DOM.
How HTMX Works:
- You add
hx-get
,hx-post
,hx-put
,hx-delete
, etc., to elements to trigger HTTP requests on events (like clicks or form submissions). - The server responds with HTML fragments, which HTMX swaps into the DOM according to the specified target and swap strategy.
- HTMX supports advanced features like request indicators, polling, WebSockets, history management, and more—all controlled via HTML attributes.
Example (HTMX):
<button hx-post="/clicked" hx-target="#result" hx-swap="outerHTML">Click Me!</button>
<div id="result"></div>
- When the button is clicked, HTMX sends a POST request to
/clicked
and replaces the#result
div with the server's response.
- Declarative HTML: Both use HTML attributes to define behavior, reducing the need for custom JavaScript.
- Server-Driven UI: Both can update the DOM with HTML fragments from the server.
- SSE Support: Both can use Server-Sent Events for real-time updates.
- Lightweight: Both are small, dependency-free libraries.
Feature | DATASTAR | HTMX |
---|---|---|
Attribute Prefix |
data-* (e.g., data-bind , data-on ) |
hx-* (e.g., hx-get , hx-post ) |
Frontend Reactivity | Yes (signals, computed state, two-way binding) | No (focuses on backend-driven updates) |
State Management | Built-in signals and computed signals | No built-in state management |
Two-way Binding | Yes (via data-bind ) |
No |
Computed Properties | Yes (data-computed ) |
No |
Backend Integration | SSE, SDKs for many languages | AJAX, SSE, WebSockets |
Actions/Helpers |
@setAll , @toggleAll , etc. |
No direct equivalent |
Use with JS Frameworks | Can be used standalone or with others | Can be used standalone or with others |
Bundle Size | ~14.5 KiB | ~10 KiB |
Philosophy | Unifies frontend and backend reactivity | Focuses on server-driven UI |
-
Complement:
- You can use DATASTAR alongside HTMX if you want to add frontend reactivity (signals, computed state, two-way binding) to an existing HTMX project.
- DATASTAR can manage local UI state and reactivity, while HTMX handles server communication and DOM updates.
- Both libraries use declarative HTML, so they can coexist in the same project, though you should avoid attribute conflicts.
-
Replace:
- DATASTAR can fully replace HTMX in most use-cases, as it provides all the backend-driven reactivity of HTMX plus robust frontend reactivity.
- With DATASTAR, you can build complex, interactive UIs without needing a separate frontend framework (like React or Vue) or HTMX.
- DATASTAR's unified approach means you can manage both frontend and backend state with a single set of
data-*
attributes and signals.
HTMX Version:
<button hx-post="/clicked" hx-target="#result" hx-swap="outerHTML">Click Me!</button>
<div id="result"></div>
DATASTAR Version:
<button data-on-click="@post('/clicked')">Click Me!</button>
<div id="result"></div>
- The DATASTAR version uses
data-on-click
and the@post
action, achieving the same result with a unified attribute style.
- HTMX is excellent for server-driven UI and declarative AJAX, but does not provide frontend reactivity or state management.
- DATASTAR offers all the power of HTMX plus a full frontend reactivity system, making it a more complete solution for modern web apps.
- You can use DATASTAR to complement HTMX or as a full replacement, depending on your project's needs.
- Use signals for all reactive state.
- Prefer declarative
data-*
attributes over imperative JavaScript. - Use backend SSE for real-time updates and server-driven UI.
- Organize signals with namespaces for complex state.
- Use computed signals for derived state.
- Use
data-indicator
for loading states. - Use actions like
@setAll
and@toggleAll
for batch updates.
DATASTAR is MIT licensed.