Skip to content
Agentmart
Submit a tool

datastar

Build reactive hypermedia web applications using Datastar.

Skill by EstebanForge

IndexedMIT★ 4
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/estebanforge-datastar

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Build reactive hypermedia web applications using Datastar. Use when developing frontend interfaces with Datastar data attributes, reactive signals, or Server-Sent Events (SSE).

Use cases: frontend, backend, data

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 26, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/datastar

What's inside

Skill name
datastar
Description
Build reactive hypermedia web applications using Datastar. Use when developing frontend interfaces with Datastar data attributes, reactive signals, or Server-Sent Events (SSE).
License
MIT
Instructions
324 lines in SKILL.md · view on GitHub

Files (4)

  • EXAMPLES.md
  • LICENSE
  • README.md
  • SKILL.md

SKILL.md (first lines)

# Datastar

Hypermedia framework. Backend drives frontend via SSE. Frontend reactivity via `data-*` attributes and signals. Single CDN include, no npm required.

**CSP note**: Datastar uses `Function()` constructors, requiring `unsafe-eval` in Content Security Policy.

## Quick Start

```html
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.2/bundles/datastar.js"></script>
```

Core pattern: `data-*` attributes on HTML elements, `$signalName` for reactive state, `@action()` for backend calls.

```html
<input data-bind:query />
<button data-on:click="@get('/search')">Search</button>
<div id="results"></div>
```

## Core Concepts

### Signals (`$`)

Reactive variables. Auto-track changes. `$` prefix required.

- **Create**: `data-signals:foo="'hello'"` or `data-bind:foo` (from input)
- **Read**: `$foo` in any expression
- **Set**: `$foo = 'new'` in any `data-on` handler
- **Computed**: `data-computed:upper="$foo.toUpperCase()"` (read-only, no side effects)
- **Nested**: `data-signals:form.name` => `$form.name`
- **Object syntax**: `data-signals="{a: 1, b: {c: 2}}"`
- **Hyphenation**: `data-bind:foo-bar` creates `$fooBar` (auto camelCase)
- **Private signals**: Names starting with `_` (e.g. `_loading`) are NOT sent to backend. Use for client-only state.
- **No `__` in names**: Double underscore is the modifier delimiter. `data-signals:foo__bar` will break.

### Modifiers (`__`)

Modifiers alter attribute behavior. Applied with double underscore syntax. Used in virtually every non-trivial app.

| Modifier | Applies to | Example |
|---|---|---|
| `__debounce.Xms` | `data-on:*` | `data-on:input__debounce.200ms="@get('/search')"` |
| `__throttle.Xms` | `data-on:*` | `data-on:scroll__throttle.100ms="..."` |
| `__window` | `data-on:*` | `data-on:keydown__window="evt.key === 'Enter' && ..."` |
| `__document` | `data-on:*` | Document-scoped events |
| `__outside` | `data-on:click` | Click-outside-to-close menus |
| `__prevent` | `data-on:*` | `data-on:click__prevent="@post('/...')"` |
| `__stop` | `data-on:*` | stopPropagation |
| `__once` | `data-on:*`, `data-on-intersect` | Single-fire listener |
| `__delay.Xms` | `data-init` | `data-init__delay.500ms="..."` |
| `__duration.Xms` or `__duration.Xs` | `data-on-interval` | `data-on-interval__duration.5s="@get('/poll')"` |
| `__duration.leading` | `data-on-interval` | Fire immediately then wait duration. e.g. `__duration.5s.leading`. Caution: infinite loops in backend-returned HTML |
| `__exit` | `data-on-intersect` | Trigger when element leaves viewport |
| `__half`, `__full` | `data-on-intersect` | Intersection thresholds (50%, 100%) |
| `__threshold.X` | `data-on-intersect` | Custom intersection threshold (e.g. `__threshold.25`) |
| `__ifmissing` | `data-signals` | `data-signals:foo__ifmissing="'default'"` only sets if not yet defined |
| `__case.camel` | `data-on:*` | Force camelCase event names |
| `__passive` | `data-on:*` | Passive event listener (scroll perf) |
| `__capture` | `data-on:*` | Capture phase |
| `__viewtransition` | `data-on:*`, `data-init`, `data-on-intersect`, `data-on-interval` | Wrap in View Transition API |
| `__self` | `data-ignore` | Ignore only element, not children |
| `__prop`, `__event` | `data-bind` | Force property binding, customize sync event |
| `__terse` | `data-json-signals` | Compact JSON output |

For exhaustive modifier lists, fetch https://data-star.dev/reference/attributes

### Data Attributes (full list)

| Attribute | Purpose | Example |
|---|---|---|
| `data-bind` | Two-way bind to input value | `data-bind:email` |
| `data-text` | Set text content | `data-text="$count"` |
| `data-show` | Show/hide (display:none) | `data-show="$isOpen"` |
| `data-class` | Toggle CSS class | `data-class:active="$selected"` |
| `data-attr` | Set any HTML attribute | `data-attr:disabled="$saving"` |
| `data-style` | Set inline style | `data-style:color="'red'"` |
| `data-on` | Event listener (supports modifiers) | `data-on:click="$count++"` |
| `data-signals` | Create/update signals | `data-signals:count="0"` |
| `data-computed` | Derived read-only signal (no side effects!) | `data-computed:doubled="$n*2"` |
| `data-effect` | Run expression on signal change (for side effects) | `data-effect="console.log($foo)"` |
| `data-indicator` | Signal true while request in-flight | `data-indicator:_loading` |
| `data-init` | Run on init + re-patch | `data-init="@get('/init')"` |
| `data-ref` | Store element reference in signal | `data-ref:myEl` |
| `data-ignore` | Skip Datastar processing entirely | `data-ignore` |
| `data-ignore-morph` | Skip morphing this element | `data-ignore-morph` |
| `data-preserve-attr` | Preserve attr across morphs | `data-preserve-attr="class"` |
| `data-on-intersect` | Trigger on viewport intersection | `data-on-intersect="@get('/more')"` |
| `data-on-interval` | Trigger on timer | `data-on-interval__duration.5s="@get('/poll')"` |
| `data-on-signal-patch` | Trigger on signal change | `data-on-signal-patch="$foo"` |
| `data-on-signal-patch-filter` | Filter which signal patches trigger | `data-on-signal-patch-filter="/^form\./"` |
| `data-json-signals` | Display signals as JSON (debugging, supports `__terse` and `{include/exclude}` filters) | `data-json-signals` |

**Attribute evaluation order matters**: `data-indicator` must appear before `data-init` / backend actions in the HTML to ensure the indicator signal exists when the request fires.

### Actions (`@`)

Safe helper functions. The `@` prefix is a security sandbox; arbitrary JS cannot call these.

**Frontend:**
- `@peek(fn)` - Read signals without subscribing to changes: `@peek(() => $bar)`
- `@setAll(value, filter?)` - Bulk set signals. Value FIRST, optional filter second: `@setAll(true, {include: /^menu\./})`
- `@toggleAll(filter?)` - Bulk toggle signals: `@toggleAll({include: /^menu\.isOpen\./})`

**Backend (SSE responses):**
- `@get(url, opts)` - GET request
- `@post(url, opts)` - POST request
- `@put(url, opts)` - PUT request
- `@patch(url, opts)` - PATCH request
- `@delete(url, opts)` - DELETE request

All backend actions send all signals by default (`datastar` query param for GET, JSON body for others). Private signals (`_` prefix) excluded. Use `{filterSignals: /regex/}` to limit (not recommended; prefer sending all).

**Form submission**: Use `{contentType: 'form'}` to send as form data instead of signals. Auto-finds closest `<form>`, validates, and sends form elements. `data-on:submit` auto-prevents default.

### Expressions

JS-like strings evaluated in sandboxed context. Key differences from plain JS:
- `$signalName` auto-resolves to signal value

From EstebanForge/AGENTS, MIT.

More from EstebanForge/AGENTS

Signals

Stars
4
Forks
0
Open issues
0
Last commit (this folder)
Oct 16, 2026 (13 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from EstebanForge

Cite this page

datastar skill. Agent Mart. https://agentmart.dev/skills/estebanforge-datastar (last updated 2026-10-24)