Code & DataDataTable

DataTable

Interactive Markdown table with sorting, filtering, and pagination. A standard Markdown table becomes an enhanced data table.

Basic usage

Enable sorting and search on a Markdown table.

{% datatable sortable="Name,Price" searchable=true %}
| Name | Price | Category | Stock |
|------|-------|----------|-------|
| Widget A | $9.99 | Tools | 150 |
| Widget B | $14.99 | Tools | 85 |
| Gadget X | $24.99 | Electronics | 42 |
| Gadget Y | $19.99 | Electronics | 128 |
| Part Z | $4.99 | Components | 500 |
{% /datatable %}
<div data-rune="data-table" typeof="Dataset" data-rune-fields="{&quot;sortable&quot;:&quot;Name,Price&quot;,&quot;searchable&quot;:&quot;true&quot;,&quot;pageSize&quot;:&quot;0&quot;,&quot;defaultSort&quot;:&quot;&quot;}">
  <div data-name="scroll">
    <table data-name="table">
      <thead>
        <tr>
          <th>Name</th>
          <th>Price</th>
          <th>Category</th>
          <th>Stock</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Widget A</td>
          <td>$9.99</td>
          <td>Tools</td>
          <td>150</td>
        </tr>
        <tr>
          <td>Widget B</td>
          <td>$14.99</td>
          <td>Tools</td>
          <td>85</td>
        </tr>
        <tr>
          <td>Gadget X</td>
          <td>$24.99</td>
          <td>Electronics</td>
          <td>42</td>
        </tr>
        <tr>
          <td>Gadget Y</td>
          <td>$19.99</td>
          <td>Electronics</td>
          <td>128</td>
        </tr>
        <tr>
          <td>Part Z</td>
          <td>$4.99</td>
          <td>Components</td>
          <td>500</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
NamePriceCategoryStock
Widget A$9.99Tools150
Widget B$14.99Tools85
Gadget X$24.99Electronics42
Gadget Y$19.99Electronics128
Part Z$4.99Components500
<div typeof="Dataset" class="rf-datatable rf-datatable--true rf-datatable--Name,Price rf-datatable--0" data-searchable="true" data-sortable="Name,Price" data-page-size="0" data-default-sort="" data-elevation="sunken" data-rune="data-table" data-density="compact">
  <div data-name="scroll" class="rf-datatable__scroll">
    <table data-name="table" class="rf-datatable__table" data-section="body">
      <thead>
        <tr>
          <th>Name</th>
          <th>Price</th>
          <th>Category</th>
          <th>Stock</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Widget A</td>
          <td>$9.99</td>
          <td>Tools</td>
          <td>150</td>
        </tr>
        <tr>
          <td>Widget B</td>
          <td>$14.99</td>
          <td>Tools</td>
          <td>85</td>
        </tr>
        <tr>
          <td>Gadget X</td>
          <td>$24.99</td>
          <td>Electronics</td>
          <td>42</td>
        </tr>
        <tr>
          <td>Gadget Y</td>
          <td>$19.99</td>
          <td>Electronics</td>
          <td>128</td>
        </tr>
        <tr>
          <td>Part Z</td>
          <td>$4.99</td>
          <td>Components</td>
          <td>500</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

With pagination

Use pageSize to paginate large tables.

{% datatable sortable="Name,Price" searchable=true pageSize=3 %}
| Name | Price | Category | Stock |
|------|-------|----------|-------|
| Widget A | $9.99 | Tools | 150 |
| Widget B | $14.99 | Tools | 85 |
| Gadget X | $24.99 | Electronics | 42 |
| Gadget Y | $19.99 | Electronics | 128 |
| Part Z | $4.99 | Components | 500 |
{% /datatable %}
<div data-rune="data-table" typeof="Dataset" data-rune-fields="{&quot;sortable&quot;:&quot;Name,Price&quot;,&quot;searchable&quot;:&quot;true&quot;,&quot;pageSize&quot;:&quot;3&quot;,&quot;defaultSort&quot;:&quot;&quot;}">
  <div data-name="scroll">
    <table data-name="table">
      <thead>
        <tr>
          <th>Name</th>
          <th>Price</th>
          <th>Category</th>
          <th>Stock</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Widget A</td>
          <td>$9.99</td>
          <td>Tools</td>
          <td>150</td>
        </tr>
        <tr>
          <td>Widget B</td>
          <td>$14.99</td>
          <td>Tools</td>
          <td>85</td>
        </tr>
        <tr>
          <td>Gadget X</td>
          <td>$24.99</td>
          <td>Electronics</td>
          <td>42</td>
        </tr>
        <tr>
          <td>Gadget Y</td>
          <td>$19.99</td>
          <td>Electronics</td>
          <td>128</td>
        </tr>
        <tr>
          <td>Part Z</td>
          <td>$4.99</td>
          <td>Components</td>
          <td>500</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
NamePriceCategoryStock
Widget A$9.99Tools150
Widget B$14.99Tools85
Gadget X$24.99Electronics42
Gadget Y$19.99Electronics128
Part Z$4.99Components500
<div typeof="Dataset" class="rf-datatable rf-datatable--true rf-datatable--Name,Price rf-datatable--3" data-searchable="true" data-sortable="Name,Price" data-page-size="3" data-default-sort="" data-elevation="sunken" data-rune="data-table" data-density="compact">
  <div data-name="scroll" class="rf-datatable__scroll">
    <table data-name="table" class="rf-datatable__table" data-section="body">
      <thead>
        <tr>
          <th>Name</th>
          <th>Price</th>
          <th>Category</th>
          <th>Stock</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Widget A</td>
          <td>$9.99</td>
          <td>Tools</td>
          <td>150</td>
        </tr>
        <tr>
          <td>Widget B</td>
          <td>$14.99</td>
          <td>Tools</td>
          <td>85</td>
        </tr>
        <tr>
          <td>Gadget X</td>
          <td>$24.99</td>
          <td>Electronics</td>
          <td>42</td>
        </tr>
        <tr>
          <td>Gadget Y</td>
          <td>$19.99</td>
          <td>Electronics</td>
          <td>128</td>
        </tr>
        <tr>
          <td>Part Z</td>
          <td>$4.99</td>
          <td>Components</td>
          <td>500</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>

Attributes

AttributeTypeRequiredDescription
sortablestringColumn names to enable sorting, or "all"
searchablebooleanShow a search input to filter rows
pageSizenumberRows per page; 0 disables pagination
defaultSortstringColumn to sort by initially

Universal attributes

bg

The background layer (SPEC-088): image, video, gradient, flat overlay wash and legibility scrim, in a single injected layer behind the rune's content.

AttributeTypeRequiredDescription
bgstringBackground preset applied to this block
bg-fromstringGradient start colour — a semantic token name (→ var(--rf-color-*))
bg-gradient"to-t" | "to-b" | "to-l" | "to-r" | "to-tr" | "to-br" | "to-bl" | "to-tl"Gradient direction (bounded named set)
bg-gradient-type"linear" | "radial" | "conic"Gradient type
bg-tostringGradient end colour — a semantic token name
bg-viastringOptional middle gradient stop — a semantic token name
scrim"top" | "bottom" | "left" | "right" | "none"Scrim direction (heaviest edge); presence turns the scrim on, "none" opts out of the default cover scrim
scrim-blur"none" | "sm" | "md" | "lg"Frost scrim blur amount
scrim-strength"sm" | "md" | "lg"Gradient scrim strength
scrim-tone"dark" | "light"Whether the scrim darkens (for light text) or lightens (for dark text)
scrim-type"gradient" | "frost"Scrim treatment: gradient (default) or frost (backdrop blur)
elevation

The chrome/depth ladder (SPEC-107). The skin maps each rung to a chrome bundle by attribute, so there is no BEM class.

AttributeTypeRequiredDescription
elevation"sunken" | "flush" | "flat" | "raised" | "floating" | "overlay" | "none" | "sm" | "md" | "lg"Surface depth on the SPEC-107 ladder (sunken→overlay); none/sm/md/lg are deprecated aliases
inset

Internal padding override.

AttributeTypeRequiredDescription
inset"flush" | "tight" | "default" | "loose" | "breathe"Inner padding of this block
motion

Scroll-reveal entrance (SPEC-105). The author declares the character, the theme owns the choreography, a behaviour owns the timing.

AttributeTypeRequiredDescription
reveal"none" | "fade" | "slide" | "scale" | "blur"Scroll-reveal entrance character (none|fade|slide|scale|blur); the theme owns the choreography
staggerbooleanCascade this block's items in as it reveals (no-op on single-child runes)
spacing

Block-level rhythm override.

AttributeTypeRequiredDescription
spacing"flush" | "tight" | "default" | "loose" | "breathe"Vertical spacing above and below this block
substrate

Generated pattern fills (SPEC-087). Markers only — the engine sets the attributes and cell/opacity custom properties, CSS draws the pattern.

AttributeTypeRequiredDescription
substrate"dots" | "grid" | "lines" | "cross" | "checker" | "none"Generated surface pattern
substrate-fill"inherit" | "inset"Surface fill the pattern sits on (full colour stays with tint)
substrate-opacity"sm" | "md" | "lg"Pattern ink strength
substrate-size"sm" | "md" | "lg"Pattern cell size
substrate-target"self" | "media"Which surface the pattern fills (overrides the rune/theme default)
tint

Per-rune colour override (SPEC-053): a named tint from the theme registry, with inline per-token overrides layered on top.

AttributeTypeRequiredDescription
tintstringColor tint preset applied to this block
tint-mode"auto" | "dark" | "light"Whether the tint adapts to auto, dark, or light mode
width

The track a block rune occupies.

AttributeTypeRequiredDescription
width"compact" | "narrow" | "content" | "wide" | "full"Maximum width constraint for this block
Not availableWhy
dropcap, readingthis rune declares no prose body
framethis rune declares neither a `frameTarget` nor a media section
prominencethis rune has no page-section header