Declarative HTML

Build complex UIs with zero JavaScript using data-tx-widget attributes and tx-* child elements.

How It Works

On DOMContentLoaded, Teryx scans the document for data-tx-widget elements and instantiates widgets. A MutationObserver watches for dynamically added elements too.

<div data-tx-widget="grid" data-tx-source="/api/users" data-tx-paginated data-tx-searchable>
  <tx-column field="name" label="Name" sortable></tx-column>
  <tx-column field="email" label="Email"></tx-column>
  <tx-column field="role" label="Role" filterable></tx-column>
</div>

data-tx-* Attributes

Options are passed as data-tx-* attributes, converted from kebab-case to camelCase:

<div data-tx-widget="grid"
     data-tx-source="/api/users"
     data-tx-page-size="25"
     data-tx-paginated
     data-tx-searchable>
</div>

Type Coercion

tx-column

Grid columns as child elements:

<div data-tx-widget="grid" data-tx-source="/api/products">
  <tx-column field="name" label="Product" sortable width="200px"></tx-column>
  <tx-column field="price" label="Price" align="right" renderer="number"></tx-column>
  <tx-column field="status" label="Status" filterable filter-type="select"
    filter-options='[{"label":"Active","value":"active"},{"label":"Archived","value":"archived"}]'>
  </tx-column>
</div>
AttributeTypeDescription
fieldstringJSON field name
labelstringHeader text
sortablebooleanEnable sorting
widthstringFixed width
rendererstringBuilt-in renderer (text, number, date, boolean, badge, link, progress, actions)
filterablebooleanColumn filter
editablebooleanInline editing

tx-field

Form fields:

<div data-tx-widget="form" data-tx-action="/api/contact" data-tx-layout="vertical">
  <tx-field name="name" label="Full Name" required></tx-field>
  <tx-field name="email" label="Email" type="email" required></tx-field>
  <tx-field name="dept" label="Department" type="select"
    options='[{"label":"Engineering","value":"eng"},{"label":"Sales","value":"sales"}]'>
  </tx-field>
  <tx-field name="message" label="Message" type="textarea" rows="4"></tx-field>
</div>

tx-tab

Tab panels with inline content:

<div data-tx-widget="tabs" data-tx-variant="underline">
  <tx-tab title="Overview"><p>Overview content.</p></tx-tab>
  <tx-tab title="Settings" icon="settings"><p>Settings panel.</p></tx-tab>
</div>

tx-item / tx-step

Accordion panels, steps, and list-like widgets:

<div data-tx-widget="accordion" data-tx-multiple>
  <tx-item title="Section A" open><p>Content A.</p></tx-item>
  <tx-item title="Section B"><p>Content B.</p></tx-item>
</div>

<div data-tx-widget="steps" data-tx-current="1">
  <tx-step title="Plan" description="Choose a tier"></tx-step>
  <tx-step title="Pay" description="Billing info"></tx-step>
  <tx-step title="Confirm" description="Review"></tx-step>
</div>

tx-node

Nested tree nodes:

<div data-tx-widget="tree" data-tx-selectable data-tx-lines>
  <tx-node text="Documents" icon="folder" expanded>
    <tx-node text="report.pdf" leaf></tx-node>
    <tx-node text="slides.pptx" leaf></tx-node>
  </tx-node>
</div>

Child Element Reference

TagMaps ToUsed By
<tx-column>columnsgrid
<tx-field>fieldsform
<tx-tab>itemstabs
<tx-item>itemsaccordion, sidebar, segmented, navbar
<tx-step>itemssteps
<tx-slide>slidescarousel
<tx-node>nodestree
<tx-button>buttonsmodal
<tx-tier>tierspricing
<tx-quote>quotestestimonials
<tx-feature>itemsfeatures
<tx-event>eventscalendar
<tx-series>serieschart
<tx-option>optionsform fields
<tx-link>linksfooter
<tx-social>socialfooter
<tx-toolbar>toolbargrid
<tx-menu-item>contextMenugrid

Boolean Attributes

sortable, required, disabled, readonly, hidden, checked, multiple,
closable, active, open, expanded, leaf, collapsible, collapsed,
searchable, paginated, striped, hoverable, bordered, compact,
selectable, filterable, editable, resizable, draggable, sticky,
animated, dismissible, pill, outline, block, loading

Manual Initialization

import { configure, initWidgets } from 'teryx';
configure({ autoInit: false });
// Later:
initWidgets(document.getElementById('container'));

The declarative API produces the same output as the imperative API. Mix both freely.