DataStar HTMX Quick Start - vicmay/DATASTAR GitHub Wiki

DATASTAR Documentation

Overview

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.


Table of Contents

  1. Getting Started
  2. Core Concepts
  3. Frontend Features
  4. Backend Integration
  5. Actions
  6. Advanced Examples
  7. DATASTAR vs HTMX: Detailed Comparison and Differentiation
  8. Best Practices
  9. Community & Resources

Getting Started

Installation

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

Core Concepts

  • 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.

Understanding Signals (Reactive State)

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.

What are Signals?

  • Signals are reactive variables managed by DATASTAR.
  • They are created and updated using data-* attributes in your HTML (such as data-bind, data-computed, or data-signals).
  • When a signal changes, any DOM element or expression that references it will update automatically, without you having to write extra JavaScript.

Why are Signals Useful?

  • 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).

Basic Example

<input data-bind="username" />
<div data-text="$username"></div>
  • Here, data-bind="username" creates a signal called username.
  • The <div> will always display the current value of username.
  • If the user types in the input, the <div> updates automatically.

Computed Signals

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 of firstName and lastName.
  • If either input changes, $fullName and the displayed value update automatically.

Summary

  • 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.

Frontend Features

data-bind

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.

data-text

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>

data-computed

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>

data-show

Conditionally shows or hides an element based on an expression.

<input data-bind-input />
<button data-show="$input != ''">Save</button>

data-class

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>

data-attr

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>

data-signals

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>

data-on

Attaches event listeners and executes expressions.

<input data-bind-input />
<button data-on-click="$input = ''">Reset</button>

data-indicator

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>

Backend Integration

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'}");
});

Actions

DATASTAR provides helper actions for use in data-* attributes.

@setAll()

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>

@toggleAll()

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>

Advanced Examples

Click to Edit (Ported from HTMX)

<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>

DATASTAR vs HTMX: Detailed Comparison and Differentiation

What is HTMX?

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.

DATASTAR vs HTMX: Key Similarities

  • 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.

DATASTAR vs HTMX: Key Differences

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

How DATASTAR May Complement or Replace HTMX

  • 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.

Example: DATASTAR Replacing HTMX

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.

Summary

  • 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.

Best Practices

  • 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.

Community & Resources


License

DATASTAR is MIT licensed.

⚠️ **GitHub.com Fallback** ⚠️