The Twig API

Four spellings, one renderer. Use whichever reads best where you are.

Rendering a table

{{ craft.legs.render('price-list') }}
{{ 'price-list'|legs }}
{{ legs('price-list') }}

All three accept per-call options, which layer over the table's own settings exactly as an embed's options do:

{{ craft.legs.render('price-list', { compact: true, perPage: 10 }) }}
{{ 'price-list'|legs({ responsive: 'stack' }) }}

A handle that matches nothing renders an empty string rather than throwing. A missing table should cost you a table, not the page.

Getting the element

{% set table = craft.legs.table('price-list') %}

{{ table.title }}
{{ table.caption }}
{{ table.data.rowCount }} × {{ table.data.colCount }}
{{ table.embedCode }}

{{ table.render() }}

craft.legs.table() takes a handle or an ID and resolves in the current site.

Querying tables

craft.legs.tables() returns an ordinary element query, so everything you know about element queries applies:

{% for table in craft.legs.tables().source('query').orderBy('title asc').all() %}
  <h2>{{ table.title }}</h2>
  {{ table.render() }}
{% endfor %}

Query params of note: handle(), source() (manual, import or query), plus the usual siteId(), search(), limit() and orderBy().

Reading the grid

If you want the data rather than the markup — to feed a chart, or to build your own layout:

{% set data = craft.legs.table('price-list').data %}

{% for row in data.cells %}
  {{ row|join(', ') }}
{% endfor %}

{{ data.cell(1, 2) }}          {# row 1, column 2, zero-indexed #}
{{ data.columnLabel(2) }}      {# what the header row calls column 2 #}
{{ data.headerRows }}          {# how many rows are headers #}

The embed code

{{ craft.legs.embedCode('price-list') }}
{# → {legs:price-list:render} #}

Useful when you are building an author-facing screen of your own and want to hand someone the tag.