Visual app designer

SvStudioDesigner is the grid-centric visual data-app designer - compose a multi-entity app by arranging data-bound blocks on a canvas, then generate a runnable SvelteKit project. It's the app-level companion to the single-entity schema designer: where that authors one EntitySchema, this composes screens across many entities.

Grid-centric by design: the blocks are schema-driven and data-bound (a grid, a chart, a pivot, a dashboard, a KPI, master-detail, a faceted filter panel, a record panel, a lookup) - not arbitrary layout components. Point it at a database, get a CRUD app - kept to data views.

Just want to open it? npx @svgrid/studio designer launches this designer in your browser, auto-saves your work to studio.config.json, and writes the generated app to a folder - no host app needed. See Launch the designer.

Starting a new app

New app in the top bar walks you from nothing to a working CRUD app: pick where the data comes from, choose the tables, choose the pages, open the result.

  1. Start - sample data, your own data, or a blank set of tables you name.
  2. Data - connect a database (the table picker shows row counts and lets you preview rows before importing), read a Supabase project, pick a starter dataset, point at a REST endpoint, or paste an OpenAPI document.
  3. Screens - tick which pages each table gets (list, form, record page, dashboard) and how rows are edited: a popup form, in the grid, or on the record page.
  4. Done - name it and open it. It arrives as one undo step, so Ctrl+Z puts the previous design back.

Connecting to a live SQL database needs the local designer (npx @svgrid/studio dev) because database drivers run on your machine, not in a browser tab. Supabase is the exception: it serves its own REST API, so the wizard reads your tables with just the project URL and the anon key - it is the one real database that works from svgrid.com/studio with nothing installed. Row-level security still applies, so the app sees exactly what the browser may see. The other paths work there too, and you can rebind to any database later with Use my data.

The terminal equivalent is svgrid-studio init - the same generator, the same app. The questions differ slightly: the CLI also asks for a theme and light/dark, while the wizard offers a dashboard page per table (pick your theme in the designer afterwards).

How the screen is laid out

Here is the real designer with a small Sales App open:

The visual app designer: a Pages and Entities rail on the left, Design / Code tabs above a live grid preview (a customer grid with status chips) in the middle, and a screen properties panel on the right.

You do not need to understand the internals to use it. The same layout, labelled:

The visual designer's layout: a screens list on the left, a palette of blocks to add, a live preview in the middle, a properties panel on the right, and a Generate app button in the top bar.

The rest of this page is the detailed reference for each area, aimed at developers embedding or scripting the designer. If you just want to build an app, everything above is done by pointing and clicking - see Launch the designer.

What it edits: the project model

The designer reads and writes a StudioProject - the declarative model behind the whole app:

import { createProject } from '@svgrid/enterprise'

// One default screen (grid + edit form) per entity, in-memory.
let project = $state(createProject([customerSchema, orderSchema], { title: 'Sales App' }))
<script lang="ts">
  import { SvStudioDesigner } from '@svgrid/enterprise'
</script>

<SvStudioDesigner {project} onChange={(p) => (project = p)} />

The designer is a single IDE-style frame: a title bar (app name + accent + undo/redo + Import/Load/Save/Generate), a screen tab strip (switch, close, or add a screen), the three work panels, and a status bar (validity, entity / screen / block counts, current selection, data source).

The three panels are resizable (drag the dividers). Every edit is undoable (Ctrl/Cmd+Z, Ctrl+Shift+Z / Ctrl+Y to redo); Delete removes the selected block, Ctrl/Cmd+D (or the header button) duplicates it, and Escape deselects. Preview app opens the whole app full-screen with a Desktop / Tablet / Mobile device-width toggle to check responsiveness. Generate app opens the output in a file-tree viewer modal (scrollable, Copy per file) and a Download .zip of the complete runnable SvelteKit + Vite project - unzip, npm install, npm run dev. The zip includes package.json (with the right driver deps), vite.config.ts, svelte.config.js, tsconfig.json, the app shell, and every generated screen.

The grid (and how it edits)

The grid is the core block, so editing is a grid property, not a separate block. Select a grid and set its Editing mode:

The grid's property editor also covers Behavior (Sortable, Filtering + search, Row selection, Cell range selection, Striped rows, Totals footer row, Density), Paging (Paginate on / off, Page size, Pager position - bottom / top / both, and the Page size options for the selector), and per-Column settings - expand a column to set its header, width, alignment, pin (left / right), plus show / hide + reorder.

Editing an existing record is a grid property, not a block - the grid owns it end to end. The one thing a grid cannot give you is a form with no grid behind it, which is what the Form block is for (see below).

Form builder

Open form builder - on the grid's Form tab, and on the entity's Form layout section - opens the form in a room of its own. The canvas draws the form as it will look, with real labels, control shapes, and column spans, and you drag the fields around on it directly. Click a field to rename it, change its control, add help text, span it across the row, or give it a rule so it only appears (or only becomes required, or locks) once another answer calls for it. Group these for me sections an unarranged form in one click, and Try it swaps in the live panel so you can type into the form and watch a condition fire.

It edits the entity, not the block, so the arrangement follows the entity everywhere it is rendered - including a server-rendered screen. See edit forms.

Export toolbar

Export toolbar adds a button bar above the grid. Six options, in two groups:

Button Runs through Adds to the generated app
Export CSV / Export JSON / Copy the free grid API nothing
Export Excel (.xlsx) @svgrid/enterprise jszip
Export PDF @svgrid/enterprise pdfmake
Print @svgrid/enterprise nothing

The Excel export is real OOXML - typed number and date cells, styled headers, a frozen header row - not a renamed CSV. PDF is paginated with a repeating header, and Print opens the browser's print dialog on a paginated layout.

All six export what the user currently sees: the visible columns, in their current order, over the filtered and sorted rows. The optional dependencies are declared only for the buttons you switch on, so a CSV-only app installs neither. The canvas preview runs the same code the generated app does, so you can try a real export before generating.

The analytical + companion blocks

Beyond the grid, every block is still bound to the EntitySchema - these are data views, not generic widgets:

Block What it renders Inspector
Form A standalone create form (SvGridEditPanel, inline and blank) - a "New ticket" page, an intake screen. Its fields, sections and rules come from the entity, so a form you designed once renders the same anywhere. Heading, submit label, and what happens after saving: blank it for another entry, or go to a screen. Plus Open form builder.
Chart A chart (SvSchemaChart) - bar, pie, line, area, radar, funnel, waterfall, or treemap. Group-by dimension, measure, reduce, type.
Pivot A full pivot table (SvPivotDesigner) the end user can re-pivot live. Row + column dimensions (checkboxes), a measure, and its aggregate.
Dashboard A schema-driven KPI + chart board (SvSchemaDashboard). -
KPI A single reduced metric tile. Label, measure, reduce.
Gauge A radial gauge (SvGauge) of one reduced measure within a range - utilization, progress, scores. Label, measure, reduce, min / max, unit.
Tree A hierarchical tree (SvTree) built from the entity's own rows via a self-referential parent. A label field + a parent field (a row's link to its parent row).
Tabs A tabbed container (SvTabs) that groups display blocks into tabs - e.g. an Overview tab of KPIs + a Details tab with a chart. Add / rename / remove tabs; per tab, add child blocks (charts, KPIs, gauges, pivots, trees).
Accordion A collapsible-sections container (like Tabs, stacked vertically). Add / rename / remove sections; child blocks per section.
Master / detail A row that expands into a nested grid of related records. Child entity + foreign key.
Board A kanban board of the entity's rows, one lane per value of a group-by field, with drag between lanes. Group-by, card title / subtitle / badge fields, open-screen drill.
Calendar A month event-calendar: each row with a date lands on its day, labelled and optionally color-coded. Date field, title field, color field, open-screen drill.
Detail A full record "detail page": header, metric row, field sections, and related-record tabs - the 360 view a row action or drill-through opens. Title / subtitle / status / metric fields, sections, related child entities.
Form A standalone create / edit form for the entity. Presentation (drawer / modal / inline).
Filter panel A faceted sidebar that filters the screen's grid - enum / boolean facets pick a value, text facets search. Title + which fields become facets.
Record panel Shows the row selected in the grid - a read-only field list, or an inline edit form. Editable on / off, and (read-only) which fields to show.
Lookup Marks a relation field as a searchable picker in the edit form. The relation field.
UI component A component from the SvGrid UI kit dropped from the toolbox - entity-agnostic, works on freestanding pages too. Grouped as Actions, Inputs, Display, Feedback, Layout, and Navigation, and covering headings and prose (heading, text, link, quote, code, keyboard key, list) as well as controls, pickers, and date/time inputs. The component's own props (extracted from the component's own types, with its JSDoc as the tooltip), plus data bindings.

The filter and record panels wire to the grid on the same screen: the filter panel calls the grid controller's setFilter, and clicking a grid row publishes it to the record panel. So a common layout is a filter panel + grid + record panel three-up - list, narrow, inspect - all generated for you.

The grid, chart, pivot, and master-detail blocks are height-resizable (drag the block's bottom edge, or set Layout > Height), and the chosen height flows into the generated app. The filter and record panels size to their content.

Conditional formatting

A grid's inspector has a Conditional formatting section: add no-code rules that style a cell by its value - pick a field, a comparison (=, <, >, contains, is empty, ...), a value, and a text color / fill / bold. Rules render live in the canvas and compile to the grid's built-in conditionalFormats rule engine in the generated app (e.g. negative mrr red, status = overdue filled). It's the same engine you'd use by hand - the designer just authors the rules.

The grid's Navigation & actions section wires flow between screens: drill-through (row click opens another screen, filtered to the clicked value) and row action buttons (Edit / Delete / Open). A chart can drill too. See Navigation & row actions for the full picture.

Data sources (per entity)

Each entity binds to its own backend - the designer is not limited to one data source per app. In the inspector (no block selected), the Data source section binds the screen's entity to: