Quick Start

At the core of every Svelte Headless Table is the createTable function.

createTable creates a table instance that defines the data source and plugins to use.

Note:
Svelte Headless Table is runes-native: data is a plain array (or a getter), and everything you render is a plain reactive value. There are no stores to subscribe to.

Getting your data

In its most basic form, a table converts data items into rows, and provides columns to access the properties of each data item.

Svelte Headless Table takes the innovative approach of defining the rows and plugins first when creating a table instance, then later defining the columns used to structure the table instance.

To start, define some data and create your table with createTable.

const data = [
    { name: 'Ada Lovelace', age: 21 },
    { name: 'Barbara Liskov', age: 52 },
    { name: 'Richard Hamming', age: 38 }
]

const table = createTable(data)
const data = [
    { name: 'Ada Lovelace', age: 21 },
    { name: 'Barbara Liskov', age: 52 },
    { name: 'Richard Hamming', age: 38 }
]

const table = createTable(data)
Information:
A plain array is for data that never changes. If data needs to be updated (e.g. when lazy fetching data from the server), keep it in $state and pass a getter: createTable(() => data). See createTable. For this quick start guide, a plain array is all we need!

Defining your columns

Once we have our table instance, we can create columns to access the values of each data item.

const columns = table.createColumns([
    table.column({
        header: 'Name',
        accessor: 'name'
    }),
    table.column({
        header: 'Age',
        accessor: 'age'
    })
])
const columns = table.createColumns([
    table.column({
        header: 'Name',
        accessor: 'name'
    }),
    table.column({
        header: 'Age',
        accessor: 'age'
    })
])

Creating the view model

Now that we’ve defined our data source and columns, we can get the view model for our first table UI.

const vm = table.createViewModel(columns)
const vm = table.createViewModel(columns)

vm.current holds the finished table as plain reactive values: tableAttrs, tableBodyAttrs, headerRows, pageRows and more. Read them in the template and they update as the data or any plugin state changes.

Applying to markup

HTML tables have a standard structure.

<table>
    <thead>
        <tr>
            <th></th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td></td>
        </tr>
    </tbody>
</table>
<table>
    <thead>
        <tr>
            <th></th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td></td>
        </tr>
    </tbody>
</table>

We apply our view model over the structure. Each header row, body row and cell exposes a current object with its attrs (to spread onto the element) and props (state contributed by plugins), and vm.current exposes the table-level values.

<script>
    import { Render } from '@humanspeak/svelte-headless-table'
</script>

<table {...vm.current.tableAttrs}>
    <thead>
        {#each vm.current.headerRows as headerRow (headerRow.id)}
            <tr {...headerRow.current.attrs}>
                {#each headerRow.cells as cell (cell.id)}
                    <th {...cell.current.attrs}>
                        <Render of={cell.render()} />
                    </th>
                {/each}
            </tr>
        {/each}
    </thead>
    <tbody {...vm.current.tableBodyAttrs}>
        {#each vm.current.pageRows as row (row.id)}
            <tr {...row.current.attrs}>
                {#each row.cells as cell (cell.id)}
                    <td {...cell.current.attrs}>
                        <Render of={cell.render()} />
                    </td>
                {/each}
            </tr>
        {/each}
    </tbody>
</table>
<script>
    import { Render } from '@humanspeak/svelte-headless-table'
</script>

<table {...vm.current.tableAttrs}>
    <thead>
        {#each vm.current.headerRows as headerRow (headerRow.id)}
            <tr {...headerRow.current.attrs}>
                {#each headerRow.cells as cell (cell.id)}
                    <th {...cell.current.attrs}>
                        <Render of={cell.render()} />
                    </th>
                {/each}
            </tr>
        {/each}
    </thead>
    <tbody {...vm.current.tableBodyAttrs}>
        {#each vm.current.pageRows as row (row.id)}
            <tr {...row.current.attrs}>
                {#each row.cells as cell (cell.id)}
                    <td {...cell.current.attrs}>
                        <Render of={cell.render()} />
                    </td>
                {/each}
            </tr>
        {/each}
    </tbody>
</table>

That is the whole template: no stores, no $ prefixes, no wrapper components. Render displays each cell’s content, whether that is a plain value, a component or a snippet.

Information:
See TableViewModel and Render for everything the view model exposes. Coming from 6.x? See Migrating to v7.

Final result

Putting it all together, we have a very simple table.

NameAge
Ada Lovelace21
Barbara Liskov52
Richard Hamming38