Documentation
Table Height
Control vertical overflow with height or maxHeight. Most apps should set one of them.
Fixed height
Use a fixed height when the table should always occupy the same vertical space. The header stays visible while rows scroll.
<SimpleTable columns={columns} rows={rows} height="400px" />
<simple-table[columns]="columns"[rows]="rows"height="400px"></simple-table>
<SimpleTable:columns="columns":rows="rows"height="400px"/>
<SimpleTable {columns} {rows} height="400px" />
<SimpleTable columns={columns} rows={rows} height="400px" />
new SimpleTableVanilla(container, {columns,rows,height: "400px",});
Adaptive height (maxHeight)
Prefer maxHeight when row count varies — the table stays compact with few rows and grows up to the cap.
<SimpleTable columns={columns} rows={rows} maxHeight="600px" />
<simple-table[columns]="columns"[rows]="rows"maxHeight="600px"></simple-table>
<SimpleTable:columns="columns":rows="rows"max-height="600px"/>
<SimpleTable {columns} {rows} maxHeight="600px" />
<SimpleTable columns={columns} rows={rows} maxHeight="600px" />
new SimpleTableVanilla(container, {columns,rows,maxHeight: "600px",});
Viewport or parent size
Use vh/vw or % when the table should track the viewport or a parent with a defined height.
<SimpleTable columns={columns} rows={rows} height="50vh" />
<simple-table[columns]="columns"[rows]="rows"height="50vh"></simple-table>
<SimpleTable:columns="columns":rows="rows"height="50vh"/>
<SimpleTable {columns} {rows} height="50vh" />
<SimpleTable columns={columns} rows={rows} height="50vh" />
new SimpleTableVanilla(container, {columns,rows,height: "50vh",});
External / window scroll
Omit height and maxHeight, then set scrollParent so the page (or a custom container) drives virtualization. The header pins to that scroll viewport. More detail on Infinite Scroll.
<SimpleTable columns={columns} rows={rows} scrollParent="window" />
<simple-table[columns]="columns"[rows]="rows"scrollParent="window"></simple-table>
<SimpleTable:columns="columns":rows="rows"scroll-parent="window"/>
<SimpleTable {columns} {rows} scrollParent="window" />
<SimpleTable columns={columns} rows={rows} scrollParent="window" />
new SimpleTableVanilla(container, {columns,rows,scrollParent: "window",});
Example
Try different fixed heights below. Use Code or StackBlitz for the full example.
400px1import { useState } from "react";2import {SimpleTable} from "@simple-table/react";import type { Theme } from "@simple-table/react";3import { tableHeightConfig } from "./table-height.demo-data";4import "@simple-table/react/styles.css";56const heights = ["200px", "300px", "400px"] as const;78const TableHeightDemo = ({9 height: _height,10 theme11}: {12 height?: string | number;13 theme?: Theme;14}) => {15 const [selectedHeight, setSelectedHeight] = useState<string>("400px");1617 return (18 <div>19 <div style={{ display: "flex", gap: 8, marginBottom: 12 }}>20 {heights.map((h) => (21 <button22 key={h}23 onClick={() => setSelectedHeight(h)}24 style={{25 padding: "6px 12px",26 borderRadius: 4,27 border: "1px solid #ccc",28 background: selectedHeight === h ? "#3b82f6" : "#f3f4f6",29 color: selectedHeight === h ? "#fff" : "#374151",30 cursor: "pointer",31 fontSize: 14,32 fontWeight: 50033 }}34 >35 {h}36 </button>37 ))}38 </div>39 <SimpleTable40 columns={tableHeightConfig.headers}41 rows={tableHeightConfig.rows}42 height={selectedHeight}43 theme={theme}44 getRowId={({ row }) => row.id}45 />46 </div>47 );48};4950export default TableHeightDemo;
1import { Component, Input } from "@angular/core";2import {SimpleTableComponent} from "@simple-table/angular";import type { AngularColumnDef, GetRowIdParams, Theme } from "@simple-table/angular";3import { tableHeightConfig } from "./table-height.demo-data";4import "@simple-table/angular/styles.css";5import type { HeightDemoEmployee } from "./table-height.demo-data";67@Component({8 selector: "table-height-demo",9 standalone: true,10 imports: [SimpleTableComponent],11 template: `12 <div>13 <div style="display: flex; gap: 8px; margin-bottom: 12px">14 @for (h of heights; track h) {15 <button16 (click)="selectedHeight = h"17 [style.padding]="'6px 12px'"18 [style.borderRadius]="'4px'"19 [style.border]="'1px solid #ccc'"20 [style.background]="selectedHeight === h ? '#3b82f6' : '#f3f4f6'"21 [style.color]="selectedHeight === h ? '#fff' : '#374151'"22 [style.cursor]="'pointer'"23 [style.fontSize]="'14px'"24 [style.fontWeight]="'500'"25 >26 {{ h }}27 </button>28 }29 </div>30 <simple-table31 [getRowId]="getRowId"32 [rows]="rows"33 [columns]="headers"34 [height]="selectedHeight"35 [theme]="theme"36 ></simple-table>37 </div>38 `,39})40export class TableHeightDemoComponent {41 @Input() height: string | number = "400px";42 @Input() theme?: Theme;4344 readonly rows: HeightDemoEmployee[] = tableHeightConfig.rows;45 readonly headers: AngularColumnDef<HeightDemoEmployee>[] = tableHeightConfig.headers;46 readonly heights = ["200px", "300px", "400px"];47 selectedHeight = "400px";4849 getRowId = ({ row }: GetRowIdParams<HeightDemoEmployee>) => row.id;50}515253// table-height.demo-data.ts54// Self-contained demo table setup for this example.55import type { AngularColumnDef } from "@simple-table/angular";5657export interface HeightDemoEmployee {58 id: number;59 name: string;60 email: string;61 role: string;62 department: string;63 status: string;64}6566export const tableHeightHeaders: AngularColumnDef<HeightDemoEmployee>[] = [67 { accessor: "id", label: "ID", width: 80, type: "number" },68 { accessor: "name", label: "Name", minWidth: 150, width: "1fr", type: "string" },69 { accessor: "email", label: "Email", minWidth: 200, width: "1fr", type: "string" },70 { accessor: "role", label: "Role", minWidth: 150, width: "1fr", type: "string" },71 { accessor: "department", label: "Department", minWidth: 150, width: "1fr", type: "string" },72 { accessor: "status", label: "Status", width: 120, type: "string" },73];7475export const tableHeightData: HeightDemoEmployee[] = [76 { id: 1, name: "Alice Chen", email: "alice@example.com", role: "Senior Engineer", department: "Engineering", status: "Active" },77 { id: 2, name: "Bob Martinez", email: "bob@example.com", role: "Product Manager", department: "Product", status: "Active" },78 { id: 3, name: "Carol Williams", email: "carol@example.com", role: "Designer", department: "Design", status: "Active" },79 { id: 4, name: "David Kim", email: "david@example.com", role: "Data Analyst", department: "Analytics", status: "Active" },80 { id: 5, name: "Eva Patel", email: "eva@example.com", role: "DevOps Engineer", department: "Engineering", status: "On Leave" },81 { id: 6, name: "Frank Johnson", email: "frank@example.com", role: "QA Lead", department: "Engineering", status: "Active" },82 { id: 7, name: "Grace Lee", email: "grace@example.com", role: "UX Researcher", department: "Design", status: "Active" },83 { id: 8, name: "Henry Brown", email: "henry@example.com", role: "Backend Developer", department: "Engineering", status: "Active" },84 { id: 9, name: "Iris Davis", email: "iris@example.com", role: "Frontend Developer", department: "Engineering", status: "Active" },85 { id: 10, name: "Jack Wilson", email: "jack@example.com", role: "Technical Writer", department: "Documentation", status: "Active" },86 { id: 11, name: "Kate Thompson", email: "kate@example.com", role: "Security Engineer", department: "Engineering", status: "Active" },87 { id: 12, name: "Leo Garcia", email: "leo@example.com", role: "ML Engineer", department: "AI", status: "Active" },88 { id: 13, name: "Mia Anderson", email: "mia@example.com", role: "Project Manager", department: "Operations", status: "Active" },89 { id: 14, name: "Noah Taylor", email: "noah@example.com", role: "Solutions Architect", department: "Engineering", status: "Active" },90 { id: 15, name: "Olivia Moore", email: "olivia@example.com", role: "HR Manager", department: "Human Resources", status: "Active" },91];9293export const tableHeightConfig = {94 headers: tableHeightHeaders,95 rows: tableHeightData,96};97
1<template>2 <div>3 <div style="display: flex; gap: 8px; margin-bottom: 12px">4 <button5 v-for="h in heights"6 :key="h"7 @click="selectedHeight = h"8 :style="{9 padding: '6px 12px',10 borderRadius: '4px',11 border: '1px solid #ccc',12 background: selectedHeight === h ? '#3b82f6' : '#f3f4f6',13 color: selectedHeight === h ? '#fff' : '#374151',14 cursor: 'pointer',15 fontSize: '14px',16 fontWeight: '500',17 }"18 >19 {{ h }}20 </button>21 </div>22 <SimpleTable23 :columns="tableHeightConfig.headers"24 :rows="tableHeightConfig.rows"25 :get-row-id="getRowId"26 :height="selectedHeight"27 :theme="theme"28 />29 </div>30</template>3132<script setup lang="ts">33import { ref } from "vue";34import { SimpleTable } from "@simple-table/vue";35import type { Theme, GetRowIdParams } from "@simple-table/vue";36import { tableHeightConfig } from "./table-height.demo-data";37import type { HeightDemoEmployee } from "./table-height.demo-data";38import "@simple-table/vue/styles.css";3940withDefaults(defineProps<{ height?: string | number; theme?: Theme }>(), {41 height: "400px",42});4344const getRowId = ({ row }: GetRowIdParams<HeightDemoEmployee>) => row.id;4546const heights = ["200px", "300px", "400px"];47const selectedHeight = ref("400px");48</script>
1<script lang="ts">2 import { SimpleTable } from "@simple-table/svelte";3 import type { Theme, GetRowIdParams } from "@simple-table/svelte";4 import { tableHeightConfig } from "./table-height.demo-data";5 import type { HeightDemoEmployee } from "./table-height.demo-data";6 import "@simple-table/svelte/styles.css";78 let { height: _height = "400px", theme }: { height?: string | number; theme?: Theme } = $props();9 let selectedHeight = $state("400px");10 const heights = ["200px", "300px", "400px"];1112 const getRowId = ({ row }: GetRowIdParams<HeightDemoEmployee>) => row.id;13</script>1415<div>16 <div style="display: flex; gap: 8px; margin-bottom: 12px">17 {#each heights as h}18 <button19 onclick={() => selectedHeight = h}20 style="padding: 6px 12px; border-radius: 4px; border: 1px solid #ccc; background: {selectedHeight === h ? '#3b82f6' : '#f3f4f6'}; color: {selectedHeight === h ? '#fff' : '#374151'}; cursor: pointer; font-size: 14px; font-weight: 500;"21 >22 {h}23 </button>24 {/each}25 </div>26 <SimpleTable27 columns={tableHeightConfig.headers}28 rows={tableHeightConfig.rows}29 getRowId={getRowId}30 height={selectedHeight}31 {theme}32 />33</div>
1import { createSignal, For } from "solid-js";2import {SimpleTable} from "@simple-table/solid";import type { Theme } from "@simple-table/solid";3import { tableHeightConfig } from "./table-height.demo-data";4import "@simple-table/solid/styles.css";56const heights = ["200px", "300px", "400px"];78export default function TableHeightDemo(props: { height?: string | number; theme?: Theme }) {9 const [selectedHeight, setSelectedHeight] = createSignal("400px");1011 return (12 <div>13 <div style={{ display: "flex", gap: "8px", "margin-bottom": "12px" }}>14 <For each={heights}>15 {(h) => (16 <button17 onClick={() => setSelectedHeight(h)}18 style={{19 padding: "6px 12px",20 "border-radius": "4px",21 border: "1px solid #ccc",22 background: selectedHeight() === h ? "#3b82f6" : "#f3f4f6",23 color: selectedHeight() === h ? "#fff" : "#374151",24 cursor: "pointer",25 "font-size": "14px",26 "font-weight": "500",27 }}28 >29 {h}30 </button>31 )}32 </For>33 </div>34 <SimpleTable35 columns={tableHeightConfig.headers}36 getRowId={({ row }) => row.id}37 rows={tableHeightConfig.rows}38 height={selectedHeight()}39 theme={props.theme}40 />41 </div>42 );43}
1import { SimpleTableVanilla } from "simple-table-core";2import type { HeightDemoEmployee } from "./table-height.demo-data";3import type { Theme, GetRowIdParams } from "simple-table-core";4import { tableHeightConfig } from "./table-height.demo-data";5import "simple-table-core/styles.css";678const getRowId = ({ row }: GetRowIdParams<HeightDemoEmployee>) => row.id;9export function renderTableHeightDemo(10 container: HTMLElement,11 options?: { height?: string | number; theme?: Theme }12): SimpleTableVanilla<HeightDemoEmployee> {13 const wrapper = document.createElement("div");1415 const btnContainer = document.createElement("div");16 btnContainer.style.cssText = "display: flex; gap: 8px; margin-bottom: 12px";1718 const heights = ["200px", "300px", "400px"];19 let selectedHeight = "400px";2021 const tableContainer = document.createElement("div");22 wrapper.appendChild(btnContainer);23 wrapper.appendChild(tableContainer);24 container.appendChild(wrapper);2526 const table = new SimpleTableVanilla(tableContainer, {27 getRowId,28 columns: tableHeightConfig.headers,29 rows: tableHeightConfig.rows,30 height: selectedHeight,31 theme: options?.theme,32 });3334 const buttons: HTMLButtonElement[] = [];35 for (const h of heights) {36 const btn = document.createElement("button");37 btn.textContent = h;38 btn.style.cssText = `padding: 6px 12px; border-radius: 4px; border: 1px solid #ccc; cursor: pointer; font-size: 14px; font-weight: 500;`;39 btn.addEventListener("click", () => {40 selectedHeight = h;41 table.updateConfig({ height: h });42 updateButtons();43 });44 buttons.push(btn);45 btnContainer.appendChild(btn);46 }4748 function updateButtons() {49 buttons.forEach((btn, i) => {50 const isActive = heights[i] === selectedHeight;51 btn.style.background = isActive ? "#3b82f6" : "#f3f4f6";52 btn.style.color = isActive ? "#fff" : "#374151";53 });54 }55 updateButtons();5657 return table;58}596061// table-height.demo-data.ts62// Self-contained demo table setup for this example.63import type { ColumnDef } from "simple-table-core";6465export interface HeightDemoEmployee {66 id: number;67 name: string;68 email: string;69 role: string;70 department: string;71 status: string;72}7374export const tableHeightHeaders: ColumnDef<HeightDemoEmployee>[] = [75 { accessor: "id", label: "ID", width: 80, type: "number" },76 { accessor: "name", label: "Name", minWidth: 150, width: "1fr", type: "string" },77 { accessor: "email", label: "Email", minWidth: 200, width: "1fr", type: "string" },78 { accessor: "role", label: "Role", minWidth: 150, width: "1fr", type: "string" },79 { accessor: "department", label: "Department", minWidth: 150, width: "1fr", type: "string" },80 { accessor: "status", label: "Status", width: 120, type: "string" },81];8283export const tableHeightData: HeightDemoEmployee[] = [84 { id: 1, name: "Alice Chen", email: "alice@example.com", role: "Senior Engineer", department: "Engineering", status: "Active" },85 { id: 2, name: "Bob Martinez", email: "bob@example.com", role: "Product Manager", department: "Product", status: "Active" },86 { id: 3, name: "Carol Williams", email: "carol@example.com", role: "Designer", department: "Design", status: "Active" },87 { id: 4, name: "David Kim", email: "david@example.com", role: "Data Analyst", department: "Analytics", status: "Active" },88 { id: 5, name: "Eva Patel", email: "eva@example.com", role: "DevOps Engineer", department: "Engineering", status: "On Leave" },89 { id: 6, name: "Frank Johnson", email: "frank@example.com", role: "QA Lead", department: "Engineering", status: "Active" },90 { id: 7, name: "Grace Lee", email: "grace@example.com", role: "UX Researcher", department: "Design", status: "Active" },91 { id: 8, name: "Henry Brown", email: "henry@example.com", role: "Backend Developer", department: "Engineering", status: "Active" },92 { id: 9, name: "Iris Davis", email: "iris@example.com", role: "Frontend Developer", department: "Engineering", status: "Active" },93 { id: 10, name: "Jack Wilson", email: "jack@example.com", role: "Technical Writer", department: "Documentation", status: "Active" },94 { id: 11, name: "Kate Thompson", email: "kate@example.com", role: "Security Engineer", department: "Engineering", status: "Active" },95 { id: 12, name: "Leo Garcia", email: "leo@example.com", role: "ML Engineer", department: "AI", status: "Active" },96 { id: 13, name: "Mia Anderson", email: "mia@example.com", role: "Project Manager", department: "Operations", status: "Active" },97 { id: 14, name: "Noah Taylor", email: "noah@example.com", role: "Solutions Architect", department: "Engineering", status: "Active" },98 { id: 15, name: "Olivia Moore", email: "olivia@example.com", role: "HR Manager", department: "Human Resources", status: "Active" },99];100101export const tableHeightConfig = {102 headers: tableHeightHeaders,103 rows: tableHeightData,104};105
height vs maxHeight
height always fills the space you set. maxHeight shrinks with few rows. If both are set, height is ignored.
Rarely needed: customTheme header/footer height
Only for pagination tables with custom footers that need measured layout before paint. See Custom Theme.
Props
Height Configuration
| Property | Required | Description | Example |
|---|---|---|---|
Property | Required | Description | Example |
heightstring | number | Optional | Fixed height for the table container. The table scrolls internally with a sticky header. If both height and maxHeight are set, height is ignored. | |
maxHeightstring | number | Optional | Maximum height with adaptive sizing — the table shrinks when there are fewer rows, and grows up to this cap. Virtualization stays enabled. |