Skip to content

Data Display

Honeycomb provides two primary data display systems: DataTable for tabular data and Charts for visualizations. Both are thin Svelte wrappers around established libraries.

Import: $lib/components/ui/data-table

The data table system wraps @tanstack/table-core with a Svelte-specific reactive adapter. It does not include a pre-built <DataTable> component — instead, you use the createSvelteTable function with standard TanStack Table column definitions and render the markup yourself.

ExportDescription
createSvelteTableCreates a reactive TanStack Table instance for Svelte
FlexRenderRenders column definitions that can be strings, functions, components, or snippets
renderComponentHelper to use a Svelte component in a column definition
renderSnippetHelper to use a Svelte snippet in a column definition
<script lang="ts">
import {
createSvelteTable,
FlexRender,
renderComponent,
} from "$lib/components/ui/data-table";
import {
createColumnHelper,
getCoreRowModel,
} from "@tanstack/table-core";
import * as Table from "$lib/components/ui/table";
type User = { id: string; name: string; email: string; role: string };
let { data }: { data: User[] } = $props();
const columnHelper = createColumnHelper<User>();
const columns = [
columnHelper.accessor("name", {
header: () => "Name",
cell: (info) => info.getValue(),
}),
columnHelper.accessor("email", {
header: () => "Email",
}),
columnHelper.accessor("role", {
header: () => "Role",
}),
];
const table = createSvelteTable({
get data() { return data; },
columns,
getCoreRowModel: getCoreRowModel(),
});
</script>
<Table.Root>
<Table.Header>
{#each table.getHeaderGroups() as headerGroup}
<Table.Row>
{#each headerGroup.headers as header}
<Table.Head>
<FlexRender
content={header.column.columnDef.header}
context={header.getContext()}
/>
</Table.Head>
{/each}
</Table.Row>
{/each}
</Table.Header>
<Table.Body>
{#each table.getRowModel().rows as row}
<Table.Row>
{#each row.getVisibleCells() as cell}
<Table.Cell>
<FlexRender
content={cell.column.columnDef.cell}
context={cell.getContext()}
/>
</Table.Cell>
{/each}
</Table.Row>
{/each}
</Table.Body>
</Table.Root>

Use renderComponent to render a Svelte component inside a cell, or renderSnippet for inline snippets:

import StatusBadge from "./status-badge.svelte";
columnHelper.accessor("status", {
header: () => "Status",
cell: (cell) => renderComponent(StatusBadge, {
status: cell.getValue(),
}),
});

The function wraps TanStack’s createTable with Svelte 5 reactivity:

  1. It creates a $state for the table state.
  2. An $effect.pre re-syncs options whenever reactive dependencies change.
  3. A custom mergeObjects proxy lazily merges configuration without triggering unnecessary re-renders.

Since this wraps TanStack Table, you get access to the full feature set:

  • Sorting (getSortedRowModel)
  • Filtering (getFilteredRowModel)
  • Pagination (getPaginationRowModel)
  • Column visibility
  • Row selection
  • Column resizing
  • Grouping and aggregation

Refer to the TanStack Table documentation for full API details.


Import: $lib/components/ui/chart

The chart system combines LayerChart (a Svelte-native charting library) with D3 scales and shapes for data transformations.

PackageVersionRole
layerchart^2.0.0-next.43Svelte chart components (Area, Bar, Line, Pie, etc.)
d3-scale^4.0.2Scale functions (linear, time, band, etc.)
d3-shape^3.2.0Shape generators (area, line, arc, etc.)
ExportDescription
ChartContainerWrapper that provides chart config context and applies base styling
ChartTooltipStyled tooltip component for chart hover states
ChartConfigType for defining series labels, colors, and icons
getPayloadConfigFromPayloadUtility to extract config for a tooltip payload item

The config object maps series keys to display properties:

type ChartConfig = {
[key: string]: {
label?: string;
icon?: Component;
} & (
| { color?: string; theme?: never }
| { color?: never; theme: Record<"light" | "dark", string> }
);
};
<script lang="ts">
import { ChartContainer, type ChartConfig } from "$lib/components/ui/chart";
import { Chart, Svg, Axis, Bar, Tooltip } from "layerchart";
import { scaleBand, scaleLinear } from "d3-scale";
let { data } = $props();
const config: ChartConfig = {
revenue: { label: "Revenue", color: "hsl(var(--chart-1))" },
expenses: { label: "Expenses", color: "hsl(var(--chart-2))" },
};
</script>
<ChartContainer {config}>
<Chart
data={data}
x="month"
xScale={scaleBand().padding(0.2)}
y="revenue"
yScale={scaleLinear()}
>
<Svg>
<Axis placement="bottom" />
<Axis placement="left" />
<Bar />
</Svg>
<Tooltip.Root>
<!-- tooltip content -->
</Tooltip.Root>
</Chart>
</ChartContainer>

The ChartContainer component applies a comprehensive set of CSS overrides to normalize LayerChart’s default appearance:

  • Removes default stroke on dots and highlight lines
  • Maintains full opacity on stacked series (no dimming on hover)
  • Hides axis tick marks and rule lines (uses grid lines instead)
  • Normalizes legend swatch sizing and spacing
  • Sets fill colors for labels and tick labels to match the design system

These overrides are applied via Tailwind utility classes targeting LayerChart’s internal CSS class names (prefixed with lc-).

Charts support light/dark mode through two mechanisms:

  1. Single color: Use CSS custom properties like hsl(var(--chart-1)) which adapt automatically.
  2. Per-theme colors: Use the theme property in ChartConfig to specify different colors for light and dark modes:
const config: ChartConfig = {
visitors: {
label: "Visitors",
theme: {
light: "hsl(220 70% 50%)",
dark: "hsl(220 70% 70%)",
},
},
};

The ChartStyle component (rendered internally by ChartContainer) generates CSS custom properties scoped to the chart instance.