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.