What Dashboards is
@texuli/data/dashboard provides a responsive widget grid. People can arrange widgets with pointer or keyboard controls. The framework-free layout engine is also available from @texuli/data/dashboard/engine. The dashboard and engine APIs are published in @texuli/[email protected], which remains in development before 1.0.
The interactive page demo uses fictional data in the browser. It does not contact a service or save filters and layouts.
Components and release status
Dashboard and DashboardWidget are in the published dashboard subpath. The FilterBar and MetricCard additions described here were released in 0.18.0 and are in development; they need @texuli/[email protected] or later.
What you get
- A grid expressed in row and column units, with responsive breakpoints and reading-order rendering.
- Pointer and keyboard move and resize controls, including announced steps and a no-drag arrange toolbar.
- Pure layout operations and bounded parsing for persisted layout data.
- Host-owned rendering and persistence: Texuli does not fetch metric data or save a dashboard for you.
Install
Install @texuli/[email protected] for the published dashboard grid. Svelte 5 is a peer dependency. Import @texuli/tokens/base.css once, then import the dashboard subpath where the view is used.
npm install @texuli/[email protected]Render a board
<script lang="ts">
import { Dashboard, DashboardWidget } from '@texuli/data/dashboard';
</script>
<Dashboard label="Operations" editable>
<DashboardWidget id="signups" title="Signups" x={0} y={0} w={4} h={2}>
<p>1,284 this week</p>
</DashboardWidget>
<DashboardWidget id="revenue" title="Revenue" x={4} y={0} w={8} h={2}>
<p>$48,200 this week</p>
</DashboardWidget>
</Dashboard>Positions and sizes are grid units, not pixels. A widget without x and y takes the first free slot. The sample values above are illustrative; connect the board to data owned by your application.
Add metric and filter controls
MetricCard and FilterBar were released in 0.18.0 and are in development. Their API examples are in the integration section.
Grid model
Each widget has a stable id and a position and size in grid units: x, y, w, and h. Optional minW, minH, maxW, maxH, and locked values constrain layout changes. The view renders widgets in row-then-column reading order.
Layout engine
@texuli/data/dashboard/engine contains framework-free pure operations. normalizeLayout reads untrusted layouts, clamps values, resolves overlap deterministically, and returns issues. moveItem, resizeItem, nudgeItem, compactLayout, and reflowLayout return a new layout or a refusal; they do not mutate the input.
Breakpoints describe the available column count. dashboardBreakpoints(12) provides a twelve-column wide grid, up to six columns at medium widths, and one column on narrow containers. A missing breakpoint layout is reflowed from the nearest available layout.
Persistence shape
serializeDashboard produces canonical JSON. Treat stored or shared data as untrusted and pass it to parseDashboard before restoring it. Parsing normalizes the layout and reports refused, dropped, or clamped entries instead of throwing.
The engine caps the input at 200 widgets, 24 columns, 8 breakpoints and 512 KiB of serialized state. See packages/data/docs/data-dashboard-engine.md for the complete types and limits.
Keep data in the host
The dashboard renders widget content supplied by the host. Fetch and transform metrics in your application, then pass formatted values and text labels into components. Texuli does not accept a data URL, run queries, or persist dashboards for you.
Persist layouts
Bind layouts and serialize updates in the host. On restore, parse the stored value as untrusted input before binding it back to the view.
<script lang="ts">
import { onMount } from 'svelte';
import {
Dashboard,
DashboardWidget,
type DashboardLayout,
parseDashboard,
serializeDashboard,
} from '@texuli/data/dashboard';
let layouts = $state<Record<string, DashboardLayout>>({});
onMount(() => {
layouts = { ...parseDashboard(localStorage.getItem('ops-dashboard') ?? '').state?.layouts };
});
</script>
<Dashboard
label="Operations"
editable
bind:layouts
onLayoutChange={() => localStorage.setItem('ops-dashboard', serializeDashboard(layouts))}
>
<DashboardWidget id="signups" title="Signups" w={4} h={2}>1,284</DashboardWidget>
</Dashboard>Filter and date controls
The published @texuli/data/filter-builder exposes the filter model and applyFilter for host-owned filtering. FilterBar from @texuli/data/filter-bar was released in 0.18.0 and is in development. It edits the same FilterGroup model used by the filter builder and data grid.
Use DateRangePicker from texuli/date to collect a date range. The host applies that range to its own sample or live data. Pass today when a deterministic preset origin is needed, such as for an SSR example or a test.
Metric cards
MetricCard was released in 0.18.0 and is in development. Its API accepts a formatted value, comparison and trend label, optional loading or empty state, and an optional sparkline snippet. The sparkline needs its own text alternative.
Keyboard and pointer
Dashboard move and resize handles are buttons. Space or Enter picks up a widget; arrow keys move or resize it by a grid step; Space or Enter drops it; Escape cancels and restores its prior layout. Tab cancels and moves focus onward. Left and right account for right-to-left direction.
The arrange toolbar also offers buttons for moving or sizing a selected widget, so a drag gesture is not required. Each step, refusal, drop, and cancellation is announced in a polite live region.
Reading order and focus
Widgets render in grid reading order and their titles are headings. When widget content overflows and scrolls, its region becomes keyboard focusable and is named by the widget heading. Content that fits does not add a tab stop.
Use a meaningful label for the dashboard region. Give each chart or sparkline a text alternative, and make each metric value and comparison understandable without color or an arrow alone.
Layout and motion
The component uses logical layout properties and keeps handles and focus visible in forced colors. Layout motion respects reduced-motion preferences; it does not animate on mount or hydration.
Status and release
The dashboard grid and engine are available in @texuli/[email protected], a pre-1.0 release that is still in development; FilterBar and MetricCard were added in 0.18.0. A new minor release under 0.x may introduce breaking changes.
Host responsibilities
- The host fetches, validates, formats and refreshes data.
- The host chooses where layouts and filters are stored and who can access them.
- Texuli does not provide a hosted dashboard service, collaboration, or automatic persistence.
- Adding and removing widgets from an existing board is a host action.
- Sync integration with
@texuli/document/syncis planned, not implemented.
The Solutions demo uses fictional, local sample data only. It is not a production analytics connection.
Agent-authored dashboards
The catalog describes dashboards with data-dashboard and data-dashboard-widget nodes. Widget bodies are ordinary catalog components. Metric data comes from a source registered by the host; the blueprint does not supply executable code or an arbitrary fetch URL.
@texuli/catalog checks that widgets are direct children of a dashboard, widget ids are unique, and the dashboard has at most 200 widgets. The host validates the draft and decides whether it is suitable to render.
Keep agent data untrusted
Parse stored layouts with parseDashboard and use the catalog validation path for blueprint content. Treat text, metric values, saved filters, and layout JSON as data. Do not turn them into HTML or construct a network request from an agent-provided string.
Skill
The Texuli skill's dashboard recipe covers the dashboard grid, widget composition, filters, metrics and visual validation. Use only the APIs available in the installed package version; FilterBar and MetricCard need @texuli/[email protected] or later.

