A Datastar Rocket version 1 web component wrapping Tom Select. Both rockets requires a Datastar Pro License.
| Field | Value |
|---|---|
VERSION |
2.0.6 |
VERSION_date |
05/25/26 |
VERSION_mess |
Uses Datastar-pro 1.0.1 - fixed same dialog on different views |
npm install
copy your datastar-pro.js file to \static
npm run dev
or
npm run start
# → http://localhost:3000| Prop | Type | Default | Description |
|---|---|---|---|
placeholder |
string | "Select..." |
Placeholder text |
max-items |
int | 1 |
Max selectable items |
options |
string (JSON) | "" |
JSON array of {value, text, ...} objects |
value |
string | "" |
Current value (comma-separated for multi); reflected back to the value attribute on change |
allow-create |
boolean | false |
Allow creating new items |
detail-field |
string | "" |
Comma-separated extra fields to render in the dropdown / selected pill (e.g. "origin,season") |
search-url |
string | "" |
Backend URL for remote search (?q= → JSON [{value,text}]) |
check-options |
boolean | false |
Checkbox multi-select with Apply/Clear buttons |
dropdown-parent |
string | "" |
Selector for the element the dropdown is rendered into (e.g. "body") |
auto-select-single |
boolean | mode-dependent | When typing narrows the dropdown to a single match, auto-resolve it (single-select: setValue + close; multi: addItem + clear textbox so the user can keep filtering). Defaults ON for single-select (max-items=1, no check-options); OFF for multi / check-options. Override either way with auto-select-single="true" / "false". Re-read live, so it can be toggled at runtime via setAttribute. |
The component emits a ts-change CustomEvent on the host element with detail.value containing the selected value(s) — comma-separated when multi-select. Bind it with data-on:ts-change.
Single select with static options (plus extra detail columns):
<div data-signals:fruit="''">
<rocket-tom-select
placeholder="Pick one..."
options='[{"value":"apple","text":"Apple","origin":"Central Asia"}]'
detail-field="origin"
data-on:ts-change="$fruit = evt.detail.value"
></rocket-tom-select>
</div>Multi-select with tagging:
<rocket-tom-select
placeholder="Choose..."
max-items="5"
options='[...]'
data-on:ts-change="$items = evt.detail.value"
></rocket-tom-select>Remote search:
<rocket-tom-select
placeholder="Search..."
search-url="/api/search"
data-on:ts-change="$user = evt.detail.value"
></rocket-tom-select>The search endpoint should accept ?q=query and return JSON: [{value, text}, ...]
Checkbox multi-select with Apply/Clear:
<rocket-tom-select
placeholder="All"
check-options
options='[{"value":"1","text":"Open"},{"value":"2","text":"Closed"}]'
data-on:ts-change="$status = evt.detail.value; @get('/api/search')"
></rocket-tom-select>When check-options is set, the dropdown shows checkboxes next to each option with Apply and Clear buttons pinned at the bottom. Selections are not committed until Apply is clicked. Clear deselects all and fires the change event. Use hyphenated check-options (not checkbox) to avoid conflicts with Datastar signal binding.
Creatable tags with backend sync:
<rocket-tom-select
placeholder="Add tags..."
max-items="10"
allow-create="true"
data-on:ts-change="$tags = evt.detail.value; @post('/api/save-tags')"
></rocket-tom-select>This is a Datastar Pro v1.0.1 JS-API component, not an RC-era <template data-rocket:>. It is implemented in static/components/tom-select-rocket.js and registered with:
import { rocket } from '/static/datastar-pro.js'
rocket('rocket-tom-select', { mode: 'light', renderOnPropChange: false, props, render, onFirstRender })- Registers the
<rocket-tom-select>element viarocket(tag, def)(light DOM,renderOnPropChange: false) - Declares typed props in
props: ({ string, number, bool }) => ({ ... })— read from plain HTML attributes - Renders a single
<select data-rocket-ref="selectEl">accessed in code asrefs.selectEl - Self-loads the Tom Select JS from the CDN by injecting a
<script>(only the CSS<link>is needed in the page) - Initializes the Tom Select instance in
onFirstRenderonce the script resolves - Syncs
optionsandvaluereactively viaobserveProps(...); on user change it reflects back to thevalueattribute and callsemit('ts-change', { value }) - Cleans up via
cleanup()— destroys the Tom Select instance when the element leaves the DOM
- Props are set as plain attributes (
placeholder="...",options='[...]') or reactively viadata-attr:— each element instance is isolated $fruit,$selectedUser, etc. are page signals — shared across the page- The
data-on:ts-changehandler bridges the component → page signals viaevt.detail.value
The component self-loads the Tom Select JS from the CDN, so only the CSS is required in the page. It uses light DOM (mode: 'light', no shadow DOM), so styles apply naturally.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tom-select@2.4.1/dist/css/tom-select.css" />A Datastar Rocket v1.0.1 JS-API web component wrapping Tabulator 6.3. Implemented in static/components/tabulator-rocket.js; demo page is tabulator-rocket.html. Unlike the Tom Select component, this one expects window.Tabulator to be preloaded — include the Tabulator JS <script> in the page.
| Prop | Type | Default | Description |
|---|---|---|---|
columns |
string (JSON) | "" |
Tabulator column definitions |
data |
string (JSON) | "" |
Row data array |
height |
string | "311px" |
CSS height for the grid |
layout |
string | "fitColumns" |
Tabulator layout mode |
placeholder |
string | "No Data" |
Empty-table message |
movable-columns |
boolean | false |
Allow column drag reorder |
resizable-columns |
boolean | true |
Allow column resize |
enable-row-click |
boolean | false |
Attach row click handlers |
selectable-rows |
boolean | false |
Show checkbox column for row selection |
initial-sort |
string (JSON) | "" |
Sort config [{column, dir}] |
initial-filters |
string (JSON) | "" |
Server-saved header filters [{field, value}], applied once the table is built |
row-index |
string | "" |
Field name to use as the Tabulator row index |
| Event | Detail | Description |
|---|---|---|
tab-row-click |
{ row } |
Fired on row click (when enable-row-click is true) |
tab-rows-selected |
{ rows } |
Fired on selection change (when selectable-rows is true) |
tab-columns-changed |
{ columns } |
Debounced 600ms on column move/resize/visibility change |
Basic grid with filters and sorting:
<rocket-tabulator
columns='[{"title":"Name","field":"name","headerFilter":true}]'
data='[{"name":"Alice"},{"name":"Bob"}]'
height="320px"
movable-columns="true"
initial-sort='[{"column":"name","dir":"asc"}]'
></rocket-tabulator>Row click with detail display:
<div data-signals:clicked="''">
<rocket-tabulator
columns='[{"title":"Name","field":"name"}]'
data='[{"name":"Alice"}]'
enable-row-click="true"
data-on:tab-row-click="$clicked = JSON.stringify(evt.detail.row)"
></rocket-tabulator>
<span data-text="$clicked"></span>
</div>Selectable rows with checkboxes:
<div data-signals:count="0">
<rocket-tabulator
columns='[{"title":"Name","field":"name"}]'
data='[{"name":"Alice"},{"name":"Bob"}]'
selectable-rows="true"
data-on:tab-rows-selected="$count = evt.detail.rows.length"
></rocket-tabulator>
<span data-text="$count + ' selected'"></span>
</div>Dynamic data swap:
<rocket-tabulator
columns='[{"title":"Name","field":"name"}]'
data='[{"name":"Alice"}]'
data-attr:data="$filteredData"
></rocket-tabulator>Use data-attr:data to bind a signal — the component calls setData() internally, preserving column state, sort, and filters.
A built-in multi-select checklist header filter with search, checkboxes, and Apply/Clear buttons. Use it by setting headerFilter: "checklistFilter" in a column definition — the component replaces the string with the actual editor function before Tabulator init.
{
title: "Dept",
field: "DeptDesc",
width: 90,
headerFilter: "checklistFilter", // activates checklist dropdown
headerFilterFunc: "in" // Tabulator built-in array filter
}Features:
- Auto-populates unique values from column data
- Search box to narrow the list
- Checkboxes for multi-selection
- Apply button commits the filter (emits the selected array; pair with
headerFilterFunc: "in"), Clear button resets it - Display shows "N selected" when active
- Dropdown appended to
document.body(position:fixed) to escape headeroverflow:hidden - Per-cell listeners are torn down on component cleanup
The same resolution pass also swaps these string placeholders in column definitions for built-in functions:
| Definition key | String value | Effect |
|---|---|---|
formatter |
"isoDate" |
Formats YYYY-MM-DD… values as MM/DD/YYYY |
formatter |
"notesWrap" |
Wrapping multi-line cell; click opens a full-text popup (also sets a truncating tooltip) |
headerFilter |
"checklistFilter" |
The multi-select checklist filter above |
A built-in column picker with visibility checkboxes and drag-to-reorder. Call it from any button via the element method:
<button data-on:click="document.getElementById('my-grid')._showColPicker(el)">
Columns
</button>
<rocket-tabulator id="my-grid" columns='...' data='...'></rocket-tabulator>Features:
- Checkboxes to toggle column visibility
- Drag handles (⠇) to reorder columns via drag-and-drop
- Calls Tabulator's
moveColumn()to reorder the grid on drop - Emits
tab-columns-changedevent after reorder or visibility change - Multi-column popup layout based on field count:
Math.ceil(fields / 30)columns- 1–30 fields → 1 column
- 31–60 fields → 2 columns
- 61–90 fields → 3 columns
- Toggle: clicking the button again closes the picker
- Appended to
document.bodywithposition:fixed
Tabulator CSS is loaded globally via <link> tag:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tabulator-tables@6.3.0/dist/css/tabulator_modern.min.css" />