Documentation
Programmatic Control API
Take full control of your table with the programmatic API. Using tableRef, you can read and modify table state, apply filters and sorting, access data, and much more - all from your code. Perfect for building custom controls, implementing save/restore functionality, or creating advanced data workflows.
No status message
React TSX
Copy
1import { useRef, useState, useMemo } from "react";2import { SimpleTable } from "@simple-table/react";3import type { Theme, TableAPI, ReactHeaderObject, CellRendererProps } from "@simple-table/react";4import {5 programmaticControlConfig,6 PROGRAMMATIC_CONTROL_STATUS_COLORS,7} from "./programmatic-control.demo-data";8import "@simple-table/react/styles.css";910const ProgrammaticControlDemo = ({11 height = "400px",12 theme,13}: {14 height?: string | number;15 theme?: Theme;16}) => {17 const tableRef = useRef<TableAPI>(null);18 const [statusMessage, setStatusMessage] = useState("No status message");1920 const headers: ReactHeaderObject[] = useMemo(21 () =>22 programmaticControlConfig.headers.map((h) => {23 if (h.accessor === "status") {24 return {25 ...h,26 cellRenderer: ({ row }: CellRendererProps) => {27 const s = String(row.status);28 const colors = PROGRAMMATIC_CONTROL_STATUS_COLORS[s] ?? {29 bg: "#f3f4f6",30 color: "#374151",31 };32 return (33 <span34 style={{35 backgroundColor: colors.bg,36 color: colors.color,37 padding: "4px 8px",38 borderRadius: 4,39 fontSize: 12,40 fontWeight: "bold",41 }}42 >43 {s}44 </span>45 );46 },47 };48 }49 return h;50 }),51 [],52 );5354 const handleSortByName = () => {55 tableRef.current?.applySortState({ accessor: "name", direction: "asc" });56 setStatusMessage("Sorted by Name (A-Z)");57 };5859 const handleSortByPrice = () => {60 tableRef.current?.applySortState({ accessor: "price", direction: "desc" });61 setStatusMessage("Sorted by Price (High to Low)");62 };6364 const handleFilterAvailable = () => {65 tableRef.current?.applyFilter({ accessor: "status", operator: "equals", value: "Available" });66 setStatusMessage("Filtered to show only Available products");67 };6869 const handleClearFilters = () => {70 tableRef.current?.clearAllFilters();71 setStatusMessage("All filters cleared");72 };7374 const handleGetInfo = () => {75 const api = tableRef.current;76 if (!api) return;77 const allRows = api.getAllRows();78 const hdrs = api.getHeaders();79 const sortState = api.getSortState();80 const filterState = api.getFilterState();81 const totalValue = allRows.reduce((sum, r) => {82 const row = r as Record<string, unknown>;83 return sum + (Number(row.price) || 0) * (Number(row.stock) || 0);84 }, 0);85 const sortInfo = sortState ? `${sortState.key.label} (${sortState.direction})` : "None";86 alert(87 `Table Info:\n• Rows: ${allRows.length}\n• Columns: ${hdrs.length}\n• Active filters: ${Object.keys(filterState).length}\n• Sort: ${sortInfo}\n• Total inventory value: $${totalValue.toFixed(2)}`,88 );89 setStatusMessage("Table info displayed");90 };9192 return (93 <div>94 <div95 style={{96 marginBottom: 12,97 padding: "8px 12px",98 backgroundColor: "#eff6ff",99 border: "1px solid #bfdbfe",100 borderRadius: 6,101 color: "#1e40af",102 fontSize: 14,103 }}104 >105 {statusMessage}106 </div>107 <div style={{ marginBottom: 12, display: "flex", gap: 8, flexWrap: "wrap" }}>108 <button onClick={handleSortByName} style={{ padding: "6px 16px" }}>109 Sort by Name (A-Z)110 </button>111 <button onClick={handleSortByPrice} style={{ padding: "6px 16px" }}>112 Sort by Price (High to Low)113 </button>114 <button onClick={handleFilterAvailable} style={{ padding: "6px 16px" }}>115 Filter: Available116 </button>117 <button onClick={handleClearFilters} style={{ padding: "6px 16px" }}>118 Clear Filters119 </button>120 <button onClick={handleGetInfo} style={{ padding: "6px 16px" }}>121 Get Table Info122 </button>123 </div>124 <SimpleTable125 ref={tableRef}126 defaultHeaders={headers}127 rows={programmaticControlConfig.rows}128 height={height}129 theme={theme}130 />131 </div>132 );133};134135export default ProgrammaticControlDemo;
Vue SFC
Copy
1<template>2 <div>3 <div4 style="5 margin-bottom: 12px;6 padding: 8px 12px;7 background-color: #eff6ff;8 border: 1px solid #bfdbfe;9 border-radius: 6px;10 color: #1e40af;11 font-size: 14px;12 "13 >14 {{ statusMessage }}15 </div>16 <div style="display: flex; gap: 8px; margin-bottom: 12px; flex-wrap: wrap">17 <button @click="handleSortByName">Sort by Name (A-Z)</button>18 <button @click="handleSortByPrice">Sort by Price (High to Low)</button>19 <button @click="handleFilterAvailable">Filter: Available</button>20 <button @click="handleClearFilters">Clear Filters</button>21 <button @click="handleGetInfo">Get Table Info</button>22 </div>23 <SimpleTable24 ref="tableRef"25 :default-headers="headers"26 :rows="programmaticControlConfig.rows"27 :height="height"28 :theme="theme"29 />30 </div>31</template>3233<script setup lang="ts">34import { ref } from "vue";35import { SimpleTable } from "@simple-table/vue";36import type { Theme, TableAPI, VueHeaderObject } from "@simple-table/vue";37import { programmaticControlConfig, PROGRAMMATIC_CONTROL_STATUS_COLORS } from "./programmatic-control.demo-data";38import "@simple-table/vue/styles.css";3940withDefaults(defineProps<{ height?: string | number; theme?: Theme }>(), {41 height: "400px",42});4344const tableRef = ref<{ getAPI: () => TableAPI | null } | null>(null);45const statusMessage = ref("No status message");4647const headers: VueHeaderObject[] = programmaticControlConfig.headers.map((h) => {48 if (h.accessor === "status") {49 return {50 ...h,51 cellRenderer: ({ row }: { row: Record<string, unknown> }) => {52 const s = String(row.status);53 const colors = PROGRAMMATIC_CONTROL_STATUS_COLORS[s] ?? { bg: "#f3f4f6", color: "#374151" };54 return `<span style="background:${colors.bg};color:${colors.color};padding:4px 8px;border-radius:4px;font-size:12px;font-weight:bold">${s}</span>`;55 },56 };57 }58 return { ...h };59});6061function handleSortByName() {62 tableRef.value?.getAPI()?.applySortState({ accessor: "name", direction: "asc" });63 statusMessage.value = "Sorted by Name (A-Z)";64}6566function handleSortByPrice() {67 tableRef.value?.getAPI()?.applySortState({ accessor: "price", direction: "desc" });68 statusMessage.value = "Sorted by Price (High to Low)";69}7071function handleFilterAvailable() {72 tableRef.value?.getAPI()?.applyFilter({ accessor: "status", operator: "equals", value: "Available" });73 statusMessage.value = "Filtered to show only Available products";74}7576function handleClearFilters() {77 tableRef.value?.getAPI()?.clearAllFilters();78 statusMessage.value = "All filters cleared";79}8081function handleGetInfo() {82 const api = tableRef.value?.getAPI();83 if (!api) return;84 const allRows = api.getAllRows();85 const hdrs = api.getHeaders();86 const sortState = api.getSortState();87 const filterState = api.getFilterState();88 const totalValue = allRows.reduce((sum, r) => sum + (r.price as number) * (r.stock as number), 0);89 const sortInfo = sortState ? `${sortState.key.label} (${sortState.direction})` : "None";90 alert(91 `Table Info:\n• Rows: ${allRows.length}\n• Columns: ${hdrs.length}\n• Active filters: ${Object.keys(filterState).length}\n• Sort: ${sortInfo}\n• Total inventory value: $${totalValue.toFixed(2)}`,92 );93 statusMessage.value = "Table info displayed";94}95</script>
Angularprogrammatic-control-demo.component.ts
Copy
1import { Component, Input, ViewChild } from "@angular/core";2import {SimpleTableComponent} from "@simple-table/angular";import type { AngularHeaderObject, Row, Theme } from "@simple-table/angular";3import { programmaticControlConfig, PROGRAMMATIC_CONTROL_STATUS_COLORS } from "./programmatic-control.demo-data";4import "@simple-table/angular/styles.css";56@Component({7 selector: "programmatic-control-demo",8 standalone: true,9 imports: [SimpleTableComponent],10 template: `11 <div>12 <div style="margin-bottom: 12px; padding: 8px 12px; background-color: #eff6ff; border: 1px solid #bfdbfe; border-radius: 6px; color: #1e40af; font-size: 14px">13 {{ statusMessage }}14 </div>15 <div style="margin-bottom: 12px; display: flex; gap: 8px; flex-wrap: wrap">16 <button (click)="sortByName()">Sort by Name (A-Z)</button>17 <button (click)="sortByPrice()">Sort by Price (High to Low)</button>18 <button (click)="filterAvailable()">Filter: Available</button>19 <button (click)="clearFilters()">Clear Filters</button>20 <button (click)="getInfo()">Get Table Info</button>21 </div>22 <simple-table23 #simpleTable24 [rows]="rows"25 [defaultHeaders]="headers"26 [height]="height"27 [theme]="theme"28 ></simple-table>29 </div>30 `,31})32export class ProgrammaticControlDemoComponent {33 @ViewChild("simpleTable") tableRef!: SimpleTableComponent;34 @Input() height: string | number = "400px";35 @Input() theme?: Theme;3637 statusMessage = "No status message";38 readonly rows: Row[] = programmaticControlConfig.rows;39 readonly headers: AngularHeaderObject[] = programmaticControlConfig.headers.map((h) => {40 if (h.accessor === "status") {41 return {42 ...h,43 cellRenderer: ({ row }: { row: Record<string, unknown> }) => {44 const s = String(row.status);45 const colors = PROGRAMMATIC_CONTROL_STATUS_COLORS[s] ?? { bg: "#f3f4f6", color: "#374151" };46 return `<span style="background:${colors.bg};color:${colors.color};padding:4px 8px;border-radius:4px;font-size:12px;font-weight:bold">${s}</span>`;47 },48 };49 }50 return { ...h };51 });5253 sortByName(): void {54 this.tableRef.getAPI()?.applySortState({ accessor: "name", direction: "asc" });55 this.statusMessage = "Sorted by Name (A-Z)";56 }5758 sortByPrice(): void {59 this.tableRef.getAPI()?.applySortState({ accessor: "price", direction: "desc" });60 this.statusMessage = "Sorted by Price (High to Low)";61 }6263 filterAvailable(): void {64 this.tableRef.getAPI()?.applyFilter({ accessor: "status", operator: "equals", value: "Available" });65 this.statusMessage = "Filtered to show only Available products";66 }6768 clearFilters(): void {69 this.tableRef.getAPI()?.clearAllFilters();70 this.statusMessage = "All filters cleared";71 }7273 getInfo(): void {74 const api = this.tableRef.getAPI();75 if (!api) return;76 const allRows = api.getAllRows();77 const hdrs = api.getHeaders();78 const sortState = api.getSortState();79 const filterState = api.getFilterState();80 const totalValue = allRows.reduce((sum, r) => {81 const data = r.row as { price?: number; stock?: number };82 return sum + (Number(data.price) || 0) * (Number(data.stock) || 0);83 }, 0);84 const sortInfo = sortState ? `${sortState.key.label} (${sortState.direction})` : "None";85 alert(86 `Table Info:\n• Rows: ${allRows.length}\n• Columns: ${hdrs.length}\n• Active filters: ${Object.keys(filterState).length}\n• Sort: ${sortInfo}\n• Total inventory value: $${totalValue.toFixed(2)}`,87 );88 this.statusMessage = "Table info displayed";89 }90}919293// programmatic-control.demo-data.ts94// Self-contained demo table setup for this example.95import type { AngularHeaderObject } from "@simple-table/angular";969798export const STATUS_COLORS: Record<string, { bg: string; color: string }> = {99 Available: { bg: "#dcfce7", color: "#166534" },100 "Low Stock": { bg: "#fef3c7", color: "#92400e" },101 "Out of Stock": { bg: "#fee2e2", color: "#991b1b" },102};103104export const programmaticControlData = [105 { id: 1, name: "Wireless Keyboard", category: "Electronics", price: 49.99, stock: 145, status: "Available" },106 { id: 2, name: "Ergonomic Mouse", category: "Electronics", price: 29.99, stock: 12, status: "Low Stock" },107 { id: 3, name: "USB-C Hub", category: "Electronics", price: 39.99, stock: 234, status: "Available" },108 { id: 4, name: "Standing Desk", category: "Furniture", price: 399.99, stock: 0, status: "Out of Stock" },109 { id: 5, name: "Office Chair", category: "Furniture", price: 249.99, stock: 56, status: "Available" },110 { id: 6, name: "Monitor Stand", category: "Furniture", price: 79.99, stock: 8, status: "Low Stock" },111 { id: 7, name: "Notebook Set", category: "Stationery", price: 12.99, stock: 445, status: "Available" },112 { id: 8, name: "Pen Collection", category: "Stationery", price: 19.99, stock: 312, status: "Available" },113 { id: 9, name: "Desk Organizer", category: "Stationery", price: 24.99, stock: 5, status: "Low Stock" },114 { id: 10, name: "Coffee Maker", category: "Appliances", price: 89.99, stock: 78, status: "Available" },115 { id: 11, name: "Electric Kettle", category: "Appliances", price: 34.99, stock: 134, status: "Available" },116 { id: 12, name: "Desk Lamp LED", category: "Appliances", price: 44.99, stock: 0, status: "Out of Stock" },117];118119export const programmaticControlHeaders: AngularHeaderObject[] = [120 { accessor: "id", label: "ID", width: 70, type: "number", isSortable: true, filterable: true },121 { accessor: "name", label: "Product Name", width: "1fr", minWidth: 150, type: "string", isSortable: true, filterable: true },122 {123 accessor: "category",124 label: "Category",125 width: 140,126 type: "enum",127 isSortable: true,128 filterable: true,129 enumOptions: ["Electronics", "Furniture", "Stationery", "Appliances"].map((v) => ({ label: v, value: v })),130 },131 { accessor: "price", label: "Price", width: 110, align: "right", type: "number", isSortable: true, filterable: true, valueFormatter: ({ value }) => `$${(value as number).toFixed(2)}` },132 { accessor: "stock", label: "Stock", width: 100, align: "right", type: "number", isSortable: true, filterable: true },133 {134 accessor: "status",135 label: "Status",136 width: 110,137 type: "enum",138 isSortable: true,139 filterable: true,140 enumOptions: ["Available", "Low Stock", "Out of Stock"].map((v) => ({ label: v, value: v })),141 },142];143144export const programmaticControlConfig = {145 headers: programmaticControlHeaders,146 rows: programmaticControlData,147} as const;148149export { STATUS_COLORS as PROGRAMMATIC_CONTROL_STATUS_COLORS };150
Svelte
Copy
1<script lang="ts">2 import { SimpleTable } from "@simple-table/svelte";3 import type { Theme, SvelteHeaderObject } from "@simple-table/svelte";4 import { programmaticControlConfig, PROGRAMMATIC_CONTROL_STATUS_COLORS } from "./programmatic-control.demo-data";5 import "@simple-table/svelte/styles.css";67 let { height = "400px", theme }: { height?: string | number; theme?: Theme } = $props();89 let tableRef: any;10 let statusMessage = $state("No status message");1112 const headers: SvelteHeaderObject[] = programmaticControlConfig.headers.map((h) => {13 if (h.accessor === "status") {14 return {15 ...h,16 cellRenderer: ({ row }: { row: Record<string, unknown> }) => {17 const s = String(row.status);18 const colors = PROGRAMMATIC_CONTROL_STATUS_COLORS[s] ?? { bg: "#f3f4f6", color: "#374151" };19 return `<span style="background:${colors.bg};color:${colors.color};padding:4px 8px;border-radius:4px;font-size:12px;font-weight:bold">${s}</span>`;20 },21 };22 }23 return { ...h };24 });2526 function handleSortByName() {27 tableRef?.getAPI()?.applySortState({ accessor: "name", direction: "asc" });28 statusMessage = "Sorted by Name (A-Z)";29 }3031 function handleSortByPrice() {32 tableRef?.getAPI()?.applySortState({ accessor: "price", direction: "desc" });33 statusMessage = "Sorted by Price (High to Low)";34 }3536 function handleFilterAvailable() {37 tableRef?.getAPI()?.applyFilter({ accessor: "status", operator: "equals", value: "Available" });38 statusMessage = "Filtered to show only Available products";39 }4041 function handleClearFilters() {42 tableRef?.getAPI()?.clearAllFilters();43 statusMessage = "All filters cleared";44 }4546 function handleGetInfo() {47 const api = tableRef?.getAPI();48 if (!api) return;49 const allRows = api.getAllRows();50 const hdrs = api.getHeaders();51 const sortState = api.getSortState();52 const filterState = api.getFilterState();53 const totalValue = allRows.reduce((sum: number, r: Record<string, unknown>) => sum + (r.price as number) * (r.stock as number), 0);54 const sortInfo = sortState ? `${sortState.key.label} (${sortState.direction})` : "None";55 alert(56 `Table Info:\n• Rows: ${allRows.length}\n• Columns: ${hdrs.length}\n• Active filters: ${Object.keys(filterState).length}\n• Sort: ${sortInfo}\n• Total inventory value: $${totalValue.toFixed(2)}`,57 );58 statusMessage = "Table info displayed";59 }60</script>6162<div>63 <div style="margin-bottom: 12px; padding: 8px 12px; background-color: #eff6ff; border: 1px solid #bfdbfe; border-radius: 6px; color: #1e40af; font-size: 14px;">64 {statusMessage}65 </div>66 <div style="display: flex; gap: 8px; margin-bottom: 12px; flex-wrap: wrap;">67 <button onclick={handleSortByName}>Sort by Name (A-Z)</button>68 <button onclick={handleSortByPrice}>Sort by Price (High to Low)</button>69 <button onclick={handleFilterAvailable}>Filter: Available</button>70 <button onclick={handleClearFilters}>Clear Filters</button>71 <button onclick={handleGetInfo}>Get Table Info</button>72 </div>73 <SimpleTable74 bind:this={tableRef}75 defaultHeaders={headers}76 rows={programmaticControlConfig.rows}77 {height}78 {theme}79 />80</div>
Solid TSX
Copy
1import { createSignal } from "solid-js";2import {SimpleTable} from "@simple-table/solid";import type { Theme, TableAPI, SolidHeaderObject, CellRendererProps } from "@simple-table/solid";3import {4 programmaticControlConfig,5 PROGRAMMATIC_CONTROL_STATUS_COLORS,6} from "./programmatic-control.demo-data";7import "@simple-table/solid/styles.css";89export default function ProgrammaticControlDemo(props: {10 height?: string | number;11 theme?: Theme;12}) {13 let tableRef: TableAPI | undefined;14 const [statusMessage, setStatusMessage] = createSignal("No status message");1516 const headers: SolidHeaderObject[] = programmaticControlConfig.headers.map((h) => {17 if (h.accessor === "status") {18 return {19 ...h,20 cellRenderer: (cr: CellRendererProps) => {21 const s = String(cr.row.status);22 const colors = PROGRAMMATIC_CONTROL_STATUS_COLORS[s] ?? {23 bg: "#f3f4f6",24 color: "#374151",25 };26 return (27 <span28 style={{29 background: colors.bg,30 color: colors.color,31 padding: "4px 8px",32 "border-radius": "4px",33 "font-size": "12px",34 "font-weight": "bold",35 }}36 >37 {s}38 </span>39 );40 },41 };42 }43 return h;44 });4546 const handleSortByName = () => {47 tableRef?.applySortState({ accessor: "name", direction: "asc" });48 setStatusMessage("Sorted by Name (A-Z)");49 };5051 const handleSortByPrice = () => {52 tableRef?.applySortState({ accessor: "price", direction: "desc" });53 setStatusMessage("Sorted by Price (High to Low)");54 };5556 const handleFilterAvailable = () => {57 tableRef?.applyFilter({ accessor: "status", operator: "equals", value: "Available" });58 setStatusMessage("Filtered to show only Available products");59 };6061 const handleClearFilters = () => {62 tableRef?.clearAllFilters();63 setStatusMessage("All filters cleared");64 };6566 const handleGetInfo = () => {67 if (!tableRef) return;68 const allRows = tableRef.getAllRows();69 const hdrs = tableRef.getHeaders();70 const sortState = tableRef.getSortState();71 const filterState = tableRef.getFilterState();72 const totalValue = allRows.reduce((sum, r) => {73 const data = r.row as { price?: number; stock?: number };74 return sum + (Number(data.price) || 0) * (Number(data.stock) || 0);75 }, 0);76 const sortInfo = sortState ? `${sortState.key.label} (${sortState.direction})` : "None";77 alert(78 `Table Info:\n• Rows: ${allRows.length}\n• Columns: ${hdrs.length}\n• Active filters: ${Object.keys(filterState).length}\n• Sort: ${sortInfo}\n• Total inventory value: $${totalValue.toFixed(2)}`,79 );80 setStatusMessage("Table info displayed");81 };8283 return (84 <div>85 <div86 style={{87 "margin-bottom": "12px",88 padding: "8px 12px",89 "background-color": "#eff6ff",90 border: "1px solid #bfdbfe",91 "border-radius": "6px",92 color: "#1e40af",93 "font-size": "14px",94 }}95 >96 {statusMessage()}97 </div>98 <div style={{ "margin-bottom": "12px", display: "flex", gap: "8px", "flex-wrap": "wrap" }}>99 <button onClick={handleSortByName}>Sort by Name (A-Z)</button>100 <button onClick={handleSortByPrice}>Sort by Price (High to Low)</button>101 <button onClick={handleFilterAvailable}>Filter: Available</button>102 <button onClick={handleClearFilters}>Clear Filters</button>103 <button onClick={handleGetInfo}>Get Table Info</button>104 </div>105 <SimpleTable106 ref={(api) => (tableRef = api)}107 defaultHeaders={headers}108 rows={programmaticControlConfig.rows}109 height={props.height ?? "400px"}110 theme={props.theme}111 />112 </div>113 );114}
TypeScriptProgrammaticControlDemo.ts
Copy
1import { SimpleTableVanilla } from "simple-table-core";2import type { Theme, HeaderObject } from "simple-table-core";3import {4 programmaticControlConfig,5 PROGRAMMATIC_CONTROL_STATUS_COLORS,6} from "./programmatic-control.demo-data";7import "simple-table-core/styles.css";89export function renderProgrammaticControlDemo(10 container: HTMLElement,11 options?: { height?: string | number; theme?: Theme },12): SimpleTableVanilla {13 const wrapper = document.createElement("div");1415 const banner = document.createElement("div");16 banner.style.cssText =17 "margin-bottom:12px;padding:8px 12px;background-color:#eff6ff;border:1px solid #bfdbfe;border-radius:6px;color:#1e40af;font-size:14px";18 banner.textContent = "No status message";19 wrapper.appendChild(banner);2021 const controls = document.createElement("div");22 controls.style.cssText = "margin-bottom:12px;display:flex;gap:8px;flex-wrap:wrap";2324 const headers: HeaderObject[] = programmaticControlConfig.headers.map((h) => {25 if (h.accessor === "status") {26 return {27 ...h,28 cellRenderer: ({ row }: { row: Record<string, unknown> }) => {29 const s = String(row.status);30 const colors = PROGRAMMATIC_CONTROL_STATUS_COLORS[s] ?? {31 bg: "#f3f4f6",32 color: "#374151",33 };34 return `<span style="background:${colors.bg};color:${colors.color};padding:4px 8px;border-radius:4px;font-size:12px;font-weight:bold">${s}</span>`;35 },36 };37 }38 return { ...h };39 });4041 let table: SimpleTableVanilla;4243 function setStatus(msg: string) {44 banner.textContent = msg;45 }4647 const buttons: Array<{ label: string; action: () => void }> = [48 {49 label: "Sort by Name (A-Z)",50 action: () => {51 table.getAPI().applySortState({ accessor: "name", direction: "asc" });52 setStatus("Sorted by Name (A-Z)");53 },54 },55 {56 label: "Sort by Price (High to Low)",57 action: () => {58 table.getAPI().applySortState({ accessor: "price", direction: "desc" });59 setStatus("Sorted by Price (High to Low)");60 },61 },62 {63 label: "Filter: Available",64 action: () => {65 table.getAPI().applyFilter({ accessor: "status", operator: "equals", value: "Available" });66 setStatus("Filtered to show only Available products");67 },68 },69 {70 label: "Clear Filters",71 action: () => {72 table.getAPI().clearAllFilters();73 setStatus("All filters cleared");74 },75 },76 {77 label: "Get Table Info",78 action: () => {79 const api = table.getAPI();80 const allRows = api.getAllRows();81 const hdrs = api.getHeaders();82 const sortState = api.getSortState();83 const filterState = api.getFilterState();84 const totalValue = allRows.reduce(85 (sum, r) => sum + (r.row.price as number) * (r.row.stock as number),86 0,87 );88 const sortInfo = sortState ? `${sortState.key.label} (${sortState.direction})` : "None";89 alert(90 `Table Info:\n• Rows: ${allRows.length}\n• Columns: ${hdrs.length}\n• Active filters: ${Object.keys(filterState).length}\n• Sort: ${sortInfo}\n• Total inventory value: $${totalValue.toFixed(2)}`,91 );92 setStatus("Table info displayed");93 },94 },95 ];9697 for (const { label, action } of buttons) {98 const btn = document.createElement("button");99 btn.textContent = label;100 btn.addEventListener("click", action);101 controls.appendChild(btn);102 }103104 wrapper.appendChild(controls);105106 const tableContainer = document.createElement("div");107 wrapper.appendChild(tableContainer);108 container.appendChild(wrapper);109110 table = new SimpleTableVanilla(tableContainer, {111 defaultHeaders: headers,112 rows: programmaticControlConfig.rows,113 height: options?.height ?? "400px",114 theme: options?.theme,115 });116117 return table;118}119120121// programmatic-control.demo-data.ts122// Self-contained demo table setup for this example.123import type { HeaderObject } from "simple-table-core";124125126export const STATUS_COLORS: Record<string, { bg: string; color: string }> = {127 Available: { bg: "#dcfce7", color: "#166534" },128 "Low Stock": { bg: "#fef3c7", color: "#92400e" },129 "Out of Stock": { bg: "#fee2e2", color: "#991b1b" },130};131132export const programmaticControlData = [133 { id: 1, name: "Wireless Keyboard", category: "Electronics", price: 49.99, stock: 145, status: "Available" },134 { id: 2, name: "Ergonomic Mouse", category: "Electronics", price: 29.99, stock: 12, status: "Low Stock" },135 { id: 3, name: "USB-C Hub", category: "Electronics", price: 39.99, stock: 234, status: "Available" },136 { id: 4, name: "Standing Desk", category: "Furniture", price: 399.99, stock: 0, status: "Out of Stock" },137 { id: 5, name: "Office Chair", category: "Furniture", price: 249.99, stock: 56, status: "Available" },138 { id: 6, name: "Monitor Stand", category: "Furniture", price: 79.99, stock: 8, status: "Low Stock" },139 { id: 7, name: "Notebook Set", category: "Stationery", price: 12.99, stock: 445, status: "Available" },140 { id: 8, name: "Pen Collection", category: "Stationery", price: 19.99, stock: 312, status: "Available" },141 { id: 9, name: "Desk Organizer", category: "Stationery", price: 24.99, stock: 5, status: "Low Stock" },142 { id: 10, name: "Coffee Maker", category: "Appliances", price: 89.99, stock: 78, status: "Available" },143 { id: 11, name: "Electric Kettle", category: "Appliances", price: 34.99, stock: 134, status: "Available" },144 { id: 12, name: "Desk Lamp LED", category: "Appliances", price: 44.99, stock: 0, status: "Out of Stock" },145];146147export const programmaticControlHeaders: HeaderObject[] = [148 { accessor: "id", label: "ID", width: 70, type: "number", isSortable: true, filterable: true },149 { accessor: "name", label: "Product Name", width: "1fr", minWidth: 150, type: "string", isSortable: true, filterable: true },150 {151 accessor: "category",152 label: "Category",153 width: 140,154 type: "enum",155 isSortable: true,156 filterable: true,157 enumOptions: ["Electronics", "Furniture", "Stationery", "Appliances"].map((v) => ({ label: v, value: v })),158 },159 { accessor: "price", label: "Price", width: 110, align: "right", type: "number", isSortable: true, filterable: true, valueFormatter: ({ value }) => `$${(value as number).toFixed(2)}` },160 { accessor: "stock", label: "Stock", width: 100, align: "right", type: "number", isSortable: true, filterable: true },161 {162 accessor: "status",163 label: "Status",164 width: 110,165 type: "enum",166 isSortable: true,167 filterable: true,168 enumOptions: ["Available", "Low Stock", "Out of Stock"].map((v) => ({ label: v, value: v })),169 },170];171172export const programmaticControlConfig = {173 headers: programmaticControlHeaders,174 rows: programmaticControlData,175} as const;176177export { STATUS_COLORS as PROGRAMMATIC_CONTROL_STATUS_COLORS };178
API Methods
The following methods are available on the tableRef for programmatic control of the table.
Data Manipulation Methods
| Property | Required | Description | Example |
|---|---|---|---|
Property | Required | Description | Example |
updateData(params: { accessor: Accessor; rowIndex: number; newValue: CellValue }) => void | Optional | Programmatically update a specific cell value in the table. Useful for live updates and real-time data changes. Triggers cellUpdateFlash animation if enabled. | |
setHeaderRename(params: { accessor: Accessor }) => void | Optional | Programmatically triggers the header rename mode for a specific column. Sets the header cell to editing mode, allowing the user to rename it. The header must have enableHeaderRename enabled. |
Data Access Methods
| Property | Required | Description | Example |
|---|---|---|---|
Property | Required | Description | Example |
getVisibleRows() => TableRow[] | Optional | Returns the currently visible rows in the table. When pagination is enabled, this returns only the rows on the current page. When filters are applied, returns only filtered rows. This is useful for getting a snapshot of what the user is currently viewing. | |
getAllRows() => TableRow[] | Optional | Returns all rows in the table as TableRow objects, flattened and including nested/grouped rows. Each TableRow contains the raw row data plus metadata like depth, position, and rowPath. Unlike getVisibleRows, this returns the complete dataset regardless of pagination, filters, or grouping state. Perfect for exporting complete data, analytics, or batch operations. | |
getHeaders() => HeaderObject[] | Optional | Returns the table's current header/column definitions. Includes all column configuration such as accessors, labels, types, and formatting options. Useful for dynamic table manipulation, export configurations, or building custom UI controls. |
Export Methods
| Property | Required | Description | Example |
|---|---|---|---|
Property | Required | Description | Example |
exportToCSV | Optional | Exports the current table data to a CSV file. Respects active filters and sorting. Optionally accepts a props object to customize the filename. |
Sorting, Filtering, and Pagination Methods
| Property | Required | Description | Example |
|---|---|---|---|
Property | Required | Description | Example |
getSortState | Optional | Returns the current sort state of the table. Returns null if no sorting is applied, or a SortColumn object containing the sorted column and direction. Useful for persisting table state, synchronizing with external state management, or implementing custom sort UI. | |
| Optional | Programmatically applies a sort state to the table. Pass a column accessor and optional direction to sort, or undefined to clear sorting. If direction is omitted, the sort cycles through: asc → desc → removed. This method is async and returns a Promise. Perfect for implementing custom sort controls or coordinating sorting with external data sources. | ||
getFilterState | Optional | Returns the current filter state of the table as a TableFilterState object. The object contains all active filters keyed by unique filter IDs. Each filter includes the column accessor, operator, and values. Useful for debugging, persisting filter state, or building custom filter UI. | |
applyFilter | Optional | Programmatically applies a filter to a specific column. Accepts a FilterCondition object specifying the column accessor, filter operator, and value(s). This method is async and returns a Promise. Supports all filter operators including equals, contains, greaterThan, between, and more. Perfect for implementing custom filter UI, applying saved filters, or creating filter presets. | |
clearFilter | Optional | Clears the filter for a specific column identified by its accessor. This method is async and returns a Promise. Only removes filters applied to the specified column, leaving other column filters intact. Useful for implementing 'clear filter' buttons on individual columns or resetting specific filters programmatically. | |
clearAllFilters() => Promise<void> | Optional | Clears all active filters from the table at once. This method is async and returns a Promise. Resets the table to show all data without any filtering applied. Perfect for 'reset all filters' buttons or starting fresh with filter state. | |
setQuickFilter(text: string) => void | Optional | Programmatically sets the quick filter text. This allows you to control the global search/quick filter from your code. Pass a string to set the filter text, or an empty string to clear it. The filter will use the mode and other settings from the quickFilter prop configuration. | |
getCurrentPage() => number | Optional | Returns the current page number when pagination is enabled. Page numbers are 1-indexed (first page is 1, not 0). Returns the current page regardless of whether pagination is client-side or server-side. Useful for tracking user navigation, syncing with URL parameters, or building custom pagination UI. | |
setPage(page: number) => Promise<void> | Optional | Programmatically navigates to a specific page when pagination is enabled. Accepts a 1-indexed page number (first page is 1). This method is async and returns a Promise. Works with both client-side and server-side pagination. If the page number is out of range, it will be clamped to valid bounds. Triggers the onPageChange callback when the page changes. Perfect for implementing custom pagination controls, deep linking, or restoring saved pagination state. |
Column editor and pin layout
| Property | Required | Description | Example |
|---|---|---|---|
Property | Required | Description | Example |
toggleColumnEditor(open?: boolean) => void | Optional | Opens, closes, or toggles the column editor menu programmatically. When called without arguments, it toggles the current state (open if closed, close if open). Pass true to explicitly open the menu, or false to explicitly close it. This gives you full control over when the column editor UI is displayed, enabling custom column visibility workflows and user experiences. | |
applyColumnVisibility | Optional | Programmatically controls which columns are visible in the table. Accepts a partial or complete visibility state object where keys are column accessors and values are booleans (true = visible, false = hidden). This method is async and returns a Promise. You can pass just the columns you want to change, and other columns will maintain their current visibility state. Perfect for implementing custom column visibility presets, views, or user preferences. | |
| Optional | Returns { left, main, right }: root accessors in each pin band. Use with applyPinnedState to save and restore layout. | ||
| Optional | Set column order and pin sides in one call. Each root accessor must appear exactly once across left, main, and right. Columns with isEssential keep required order within each section. |
🎉 New in v2.1.0: Row Grouping Control
Programmatically control row grouping expansion with depth-based methods. Perfect for implementing custom expand/collapse controls, saving expansion state, or creating progressive disclosure patterns.
Row Grouping Control Methods (v2.1.0)
| Property | Required | Description | Example |
|---|---|---|---|
Property | Required | Description | Example |
expandAll() => void | Optional | Expands all rows at all depths in the table. When working with hierarchical/grouped data, this will expand every level of the hierarchy, revealing all nested rows. Useful for 'expand all' buttons or when you want to show the complete data structure to users. | |
collapseAll() => void | Optional | Collapses all rows at all depths in the table. When working with hierarchical/grouped data, this will collapse every level of the hierarchy, hiding all nested rows. Perfect for 'collapse all' buttons or resetting the table to a compact view. | |
expandDepth(depth: number) => void | Optional | Expands all rows at a specific depth level (0-indexed). Depth 0 represents the top-level rows, depth 1 is the first nested level, depth 2 is the second nested level, and so on. This allows granular control over which hierarchy levels are visible. Useful for showing specific levels of detail without expanding everything. | |
collapseDepth(depth: number) => void | Optional | Collapses all rows at a specific depth level (0-indexed). Depth 0 represents the top-level rows, depth 1 is the first nested level, and so on. This allows you to selectively hide specific hierarchy levels while keeping others visible. Useful for managing complex hierarchies and controlling information density. | |
toggleDepth(depth: number) => void | Optional | Toggles the expansion state for all rows at a specific depth level (0-indexed). If the depth is currently expanded, it will be collapsed, and vice versa. This provides a convenient way to toggle visibility of an entire hierarchy level without tracking state manually. | |
setExpandedDepths(depths: Set<number>) => void | Optional | Sets which depth levels should be expanded, replacing the current expansion state entirely. Accepts a Set of depth numbers (0-indexed). This is useful for restoring saved expansion state, implementing presets, or coordinating expansion across multiple tables. Any depth not in the Set will be collapsed. | |
getExpandedDepths() => Set<number> | Optional | Returns a Set containing all currently expanded depth levels (0-indexed). This allows you to inspect which hierarchy levels are currently visible. Useful for saving expansion state, building custom UI controls, or coordinating with other components. | |
getGroupingProperty(depth: number) => Accessor | undefined | Optional | Returns the grouping property name (accessor) for a specific depth index (0-indexed). This maps depth levels to their corresponding property names in your rowGrouping configuration. Returns undefined if the depth doesn't exist. Useful for understanding the hierarchy structure or building dynamic UI that adapts to the grouping configuration. | |
getGroupingDepth(property: Accessor) => number | Optional | Returns the depth index (0-indexed) for a specific grouping property name (accessor). This is the inverse of getGroupingProperty - it maps property names to their depth levels in the hierarchy. Returns -1 if the property is not part of the grouping configuration. Useful for programmatically determining which level a property belongs to. |