
Product
Socket MCP Adds Org Alerts, Threat Feed Review, and Package Inspection
Socket MCP now lets AI assistants review org alerts, investigate threats using the Socket threat feed, and inspect package files in addition to dependency scoring.
@isoftdata/svelte-table
Advanced tools
For the Pagination and Td components, See Pagination.md and Td.md.

pnpm i @isoftdata/svelte-table
no-rows and footer-row had to be renamed to noRows and footerRowfooter snippet/slotcolumnInfo is now powered by runes instead of a writable store
columnInfo.current rather than $columnInfo to access its valueColumnInfoRunicStore (a class) instead of ColumnInfoStoreThis component uses a generic type R to represent the type of a single row passed to the rows prop of this table. Then, R is extended by another type, IndexedRow, which includes the uuid and originalIndex properties. The original rows array you pass in will not be mutated, but the contents of filteredRows, sortedRows, and currentPageRows will be of type IndexedRow.
| Name | Type | Description | Default Value |
|---|---|---|---|
| bordered | boolean | Whether the table is bordered or not. | true |
| class | string | Any extra classes to apply to the table. | "" |
| columnClickedMethod | (column: Column, direction: SortDirection) => void | Called when a column is clicked. Should update previousSortOrder, previousSortDirection, previousSortColumn, and sortedRows. | defaultColumnClicked |
| columnHidingEnabled | boolean | When enabled, the user will be able to right click a column header and hide/show it. | false |
| columnPinningEnabled | boolean | When enabled, the user will be able to right click a column header and pin or unpin it. | false |
| columnResizingEnabled | boolean | When enabled, the user will be able to drag on the edge of a column header and resize it. | false |
| columns | Array<Column> | The definition of the columns. See columns docs below. | Required |
| currentPageNumber | number | The current page number. | 1 |
| currentPageRows | Array<IndexedRow> | It's the current page of rows to show, computed based on sortedRows, currentPageNumber, and perPageCount. The table component will set this. | sortedRows.slice(0, perPageCount) |
| filter | string | The filter string. | "" |
| filterColumnClass | ClassValue | The class for the filter column in the header row. | "col-lg-2 col-md-4 col-sm-6 align-self-end" |
| filterDisabled | boolean | Whether the filter input is disabled or not. | false |
| filterEnabled | boolean | Whether to show the filter input above the table. | false |
| filterLabel | string | The label for the filter input. | "Filter" |
| filterMethod | (filter: string, rows: Array<R>, columns: Array<Column>) => Array<IndexedRow> | A function that filters the rows based on the given filter string. Should return the rows that match the filter, with uuid (if not already specified in rows) and originalIndex properties added. | defaultFilter |
| filterPlaceholder | string | The placeholder text for the filter input. | "Filter" |
| filterProps | Array<string> | false | An array of strings that represent the properties to filter on. If false, uses all column properties. | false |
| filterReadonly | boolean | Whether the filter input is readonly or not. | false |
| filteredRows | Array<IndexedRow> | An array of objects that represent the filtered table rows. You probably don't need to interact with this. | filterMethod("", rows, columns) |
| filterLazy | boolean | number | The laziness of the filter input. true means the value will update onchange, false means oninput. A millisecond number value indicates the delay from the last UI interaction(debouncing). Consider setting a numeric value if your filter change needs to make a network call. | false |
| footers | Array<FooterValue> | Values to display in the footer. Calculated automatically by the Table component. | [] |
| rowMatchesFilterMethod | (filter: string, row: R, props: Array<RowProperties<R>>) => boolean | A function that determines whether the a given row matches the filter. Useful if you want to change how rows are matched by the filter without overriding the whole filterMethod. See Custom Filter Logic for more details | undefined |
| headerColumnClass | ClassValue | When the filter is enabled, a header slot will be inserted to the area to the left of the filter input. This is the column class for that yield's parent div. | "col" |
| headerRowClass | ClassValue | The class for the table header row. | "form-row mr-auto" |
| hideButtonClass | ClassValue | Any other classes to add the the "hide" dropdown button. | "" |
| hover | boolean | Whether the table will highlight the hovered row. | true |
| idProp | K | "uuid" | Property on the objects in the rows Array that uniquely identifies the row. Used for lazy sorting. | "uuid" |
| lastClickedIdForRange | number | IndexedRow[keyof R | "uuid"] | undefined | The last clicked ID for the range selection mode. | undefined |
| lazySort | boolean | When true, the table will only be resorted when the user clicks on a column header (not in real time as data changes). See idProp. | false |
| multiSelectEnabled | boolean | Whether to allow selecting multiple rows at a time | true |
| localStorageKey | string | undefined | If specified, the localstorage key where user-modified column info such as visibility and resizing are saved | undefined |
| parentClass | ClassValue | CSS class(es) to apply to the <table>'s parent div. | "" |
| parentStyle | string | CSS style(s) to apply to the <table>'s parent div. | "" |
| perPageCount | number | The number of rows to display per page. Enables pagination if > 0 | 0 |
| responsive | boolean | Whether the table is responsive or not. | false |
| rows | Array<R> | An array of objects that represent the table rows. | Required |
| rowSelectionIdProp | K | "uuid" | The property to use as the unique identifier for each row in the row selection feature. | "uuid" |
| rowSelectionRequiresModKey | boolean | Whether the row selection feature requires a modifier key or not. | false |
| selectionEnabled | boolean | Whether the row selection feature is enabled or not. | false |
| selectionMode | "SINGLE" | "RANGE" | null | The selection mode for the row selection feature. When multiSelectEnabled is true, both selection modes will allow you to select multiple rows. | null |
| showFilterLabel | boolean | Whether the filter label is shown or not. | false |
| showFooter | boolean | Defines if a <tfoot> should be shown. See footers slot below. | false |
| size | "sm" | "" | The size of the table. | "sm" |
| sortedRows | Array<IndexedRow> | The rows, but sorted based on sortColumn and sortDirection, and optionally filtered(See filter options below). The table component will set this. | filteredRows |
| sortDirection | "ASC" | "DESC" | The direction of the current sort. | "ASC" |
| stickyHeader | boolean | Whether the table header will stay at the top when scrolling the table. | false |
| striped | boolean | Whether the table is striped or not. | true |
| tableId | string | The unique identifier of the table. | uuid() |
| totalItemsCount | number | The total number of items in the data set. Necessary for serverside pagination and sorting since the rows array won't have every item for every page. | 0 |
| tree | boolean | When true, enables a bunch of tree-specific features. Required if you want to use TreeRows. | false |
| columnResizingEnabled | boolean | Whether the user is allowed to resizing table columns | false |
When
columnResizingEnabledistrue, any<Td>component children will have a css rule ofoverflow: hidden;applied. This makes it a column sized so small that the text doesn't fit causes the text to truncate instead of clipping outside the bounds of the cell. This is intended behavior and how most table's with resizable columns work.
You usually won't have to use these, but they're here just in case.
| Name | Type | Description | Default Value |
|---|---|---|---|
| previousSortColumn | Column | undefined | The previous sort column. | undefined |
| previousSortDirection | "ASC" | "DESC" | undefined | The previous sort direction. | undefined |
| previousSortOrder | Array<IndexedRow & { order: number }> | An array of objects that represent the previous sort order. | [] |
| selectedRowIds | Array<string | number | R[K]> | An array of strings, numbers, or objects that represent the selected row IDs. | [] |
| sortColumn | Column | undefined | The current sort column. | undefined |
| columnInfo | Writable<Record<string, Column & { visible: boolean }>> | A store containing column metadata. Mostly used for tracking column visibility. Read-only. | Handled by the component |
An Array of Objects, where the Objects have the following properties:
| Name | Type | Description |
|---|---|---|
| align | "left" | "right" | "center" | Direction to align columns (and Tds in the column) |
| class | ClassValue | Sets the class of the column header. |
| defaultSortColumn | boolean | When Svelte initalizes the view, this is the column that will be sorted by. |
| defaultSortDirection | "ASC" | "DESC" | 'ASC' or 'DESC' are the only valid options. Defaults to 'ASC' |
| ellipsis | boolean | Whether to apply text-overflow: ellipsis to the column |
| footer | See Below | Footer options for this column |
| formatter | (value: unknown) => unknown | A formatter function to use on this column. The return value will be shown in the td. |
| hideForPrint | boolean | Whether to hide this column when printing |
| icon | string | The FontAwesome icon classes for the icon you want to display, without the leading fa- |
| iconLeft | string | If you want the icon to display to the left of the name, set this to true. |
| iconPrefix | string | The FA prefix to apply. Defaults to fas. |
| minWidth | string | Will be passed in as the value for the CSS min-width property on the <th> style attribute. |
| name | string | The name of the column as it will be displayed in the table column header |
| numeric | boolean | When true, right aligns the column (and Tds in the column) and applies font-variant-numeric: tabular-nums; |
| property | string | The property name of the column. Must map to a property in the objects defined in rows(see above) |
| sortType | "ALPHA_NUM" | "STANDARD" | false | How to sort this column. Default is STANDARD. ALPHA_NUM is better for mixed number and letter columns. false will disallow sorting this column. |
| title | string | The th's title |
| unhidable | boolean | Whether to disallow hiding the column. |
| width | string | Will be passed in as the value for the CSS width property on the <th> style attribute. |
| wrap | boolean | If true, will allow column names to wrap. |
The
Columntype is generic. If you pass the type of one of yourrowsto it, then thepropertyproperty will be strongly to properties of that object. This is optional for backwards compatability reasons.

footer PropertiesBelow are the properties of the footer object
| Name | Type | Description |
|---|---|---|
| fn | "COUNT" | "AVG" | "SUM" | A function to call on each row when calculating that column's footer. |
| altProperty | string | If you want to compute footers off a different property than column.property, specify it here. |
| formatCurrency | boolean | If true, will format the column as currenty. |
| requiredValue | unknown | If specified, only column values matching this value will be included in calculations |
You can also pass a custom callback function to footer.fn, which changes some of the property types as shown below. The properties that are not repeated below behave the same whether you use a built-in or custom reducer fn.
| Name | Type | Description |
|---|---|---|
| fn | (previousValue: FooterReducerValue<R>, currentValue: FooterReducerValue<R>) => FooterReducerValue<R> | A function to call on each row when calculating that column's footer. currentValue is the value of row[property] or row[altProperty] if specified. |
| initialValue | FooterReducerValue<R> | The initial value of the reducer function. |
FooterReducerValue is a union of string, number, and the property types of the row object
| Name | Args Type | Description |
|---|---|---|
| children | [{ row: R & { originalIndex: number; uuid: string }; index: number; visibleColumnsCount: number }] | This represents one row of the table |
| header | [] | Only available if filterEnabled is true. This yields inside the first column of a <div class="form-row"></div> above the table. The 2nd column contains the filter input itself. |
| noRows | [{ visibleColumnsCount: number }] | Shown when rows.length === 0 |
| body | [{ rows: Array<R & { originalIndex: number; uuid: string }> }] | If you want to specify all of the contents of the tbody yourself, you can do so here. Specifying anything for this slot will prevent the "default" and "noRows" slot from being rendered. |
| footerRow | [{ footers: Array<FooterValue> }] | If showFooter is enabled, This is the tr where the footer values are shown. |
({ pageNumber: number }) => voidThere are a couple methods you can access by calling them on the Table component instance, which you can access using bind:this.
rowClick(row: IndexedRow): void - handles the logic for clicking on and selecting rowssetPageVisibleByItemId({ id, keyName }: { id: number | string; keyName: K }) - Given an item's id, and a keyName, sets the current page to be the one containing that itemexpandRow(rowId: (typeof selectedRowIds)[0], expanded = true) - Tree mode only. Expands a row given its id.setColumnVisibility(columnProperties: Array<string> | string, visible: boolean) - Sets the visibility of the specified column(s)setColumnVisibilityWatch(columnProperties: Array<string> | string, getVisible: () => boolean) - Sets the visibility of the specified column(s) whenever the value of getVisible changes. Call this in onMount or an effect.A handful of values are set as context of the component so they're accessible to their children.
Record<string, Column & { visible: boolean }>)There are three ways to use this component, with the difference lying in which slots are specified, which affects how table body is rendered. They are listed in order from "most automatic" to "most manual".
For this method, all you have to do is specify the rows and columns props on the Table, and do not specify anything for the default slot. For each column in each row, the table component will render a td, getting the value from that column's property prop, applying any formatter function if specified for that column.
This is the simplest method, and will work for most use cases that don't need to insert any extra HTML into the tds.
<Table
{rows}
{columns}
/>
You can still specify other slots, for example, "no-rows" and "header", just not the default slot.
<Table
{rows}
{columns}
>
{#snippet noRows({ visibleColumnsCount })}
<tr>
<td
class="text-center"
colspan={visibleColumnsCount}>No rows here bro
</td>
</tr>
{/snippet}
{#snippet header()}
<Input
label="Items per page"
class="mb-3"
type="number"
bind:value={perPageCount}
/>
{/snippet}
</Table>
For this method, you specify a single row's contents in the default slot, and access each row's value by adding let:row to the Table. These rows come from currentPageRows, so they've already been filtered, sorted, and paginated.
With this method, you can insert extra HTML into any of the td/Tds, but you have to specify them all yourself.
As above, you can still specify other slots when using this method.
<Table
{rows}
{columns}
>
{#snippet children({ row })}
<tr>
<Td property="id">
{row.id}
</Td>
<Td property="name">
{row.name}
</Td>
<Td property="email">
{row.email}
</Td>
<Td property="deleted">
<Button color="danger" icon="trash">Delete<Button>
</Td>
</tr>
{/snippet}
</Table>
With this method, you put anything you want to render in the tbody into the "body" snippet. You can access the currentPageRows with the rows property of the snippet, and the # of visible columns with visibleColumnsCount, as shown below.
This method is the most similar to how our Ractive table component works, and requires you to specify the whole contents of the tbody.
The contents of the "children" and "noRows" snippets will be ignored when using this method, but the "header" snippet will still work.
<Table
{rows}
{columns}
>
{#snippet body({ rows, visibleColumnsCount })}
{#each rows as row}
<tr>
<Td property="id">
{row.id}
</Td>
<Td property="name">
{row.name}
</Td>
<Td property="email">
{row.email}
</Td>
<Td property="deleted">
<Button color="danger" icon="trash">Delete<Button>
</Td>
</tr>
{:else}
<tr colspan={visibleColumnsCount}>No Rows.</td>
{/each}
{/snippet}
</Table>
See TreeRow.
Guides on how to extend the Table component for various common use cases
There is a fully-functioning demo at
/serversideon the demo page.
To successfully use the Table component in a context where the server/API is handling the sorting/pagination/filtering, you'll want to ensure you do the following:
sortDirection, sortColumn, perPageCount, currentPageNumber, & totalItemsCount props.filterEnabled prop to false. Alternatively, if your backend API has the ability to filter by string input, you can leave it true and pass an async function to filterMethod prop that either sets the rows or performs a state change with the now-filtered rows.pageChange callback.columnClickedMethod function. This will be called whenever the user clicks on a column.false for the sortType property on the columns definition for any columns which lack sorting support by your backend API.let:rows method of handling the rows. Instead, use the "Full Manual" option without a let:rows declaration. Example:<Table
{rows}
{columns}
sortDirection={orderByDirection}
sortColumn={columns.find(column => column.property === orderByColumn)}
perPageCount={pageSize}
{currentPageNumber}
{totalItemsCount}
>
{#snippet body({rows})}
{#each rows as row}
<tr>
<!-- your Tds here -->
</tr>
{/each}
{/snippet}
</Table
Various ways to change how the table filters rows, ordered by complexity.
filterPropsBy default, the table will check the filter against every property in the columns array. If you want to match against a different set of properties, you can specify them with the filterProps prop.
<Table
{rows}
{columns}
filterProps={['foo', 'bar']}
></Table>
rowMatchesFilterMethodBy default, the table will show any rows whose filterProps (or column properties) contain a substring of the filter string. If you want to override that logic, you can pass a rowMatchesFilterMethod.
In simple cases, you can just use the default method, and add your own logic as well:
function rowMatchesFilterMethod(filter: string, row: R, props: Array<RowProperties<R>>) {
return table?.defaultRowMatchesFilter(...args) || someOtherLogic()
}
But you can use all your own logic too.
function rowMatchesFilterMethod(filter: string, row: R, props: Array<RowProperties<R>>) {
return props.some(prop => {
// ...
})
}
filterMethodIf you really need to override some larger part of the filter logic, you can pass the filterMethod prop. This isn't recommended and is mostly a holdover from the original version of the component, but you can use it if you want to.
Enable the columnResizingEnabled prop, and pass the localStorageKey prop if you want to save the column sizes (and whether it's shown/hidden) to localstorage. These values are also stored in the columnInfo store if you want to do something else with it.
To use this component as a tree control, add the tree prop to your Table, use the TreeRow Component.
You can use the Td Component in your table to support hiding columns.
The table component will handle the Pagination Component for you.
FAQs
Unknown package
We found that @isoftdata/svelte-table demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 12 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket MCP now lets AI assistants review org alerts, investigate threats using the Socket threat feed, and inspect package files in addition to dependency scoring.

Product
Socket Firewall blocks malicious VS Code and Open VSX extensions before install, protecting developers from compromised editor marketplaces.

Research
More than 140 Mastra npm packages were compromised in a supply chain attack that used a typosquatted dependency to deliver a cross-platform infostealer during installation.