Skip to main content
View as Markdown

Pages Overview

Pages are server-rendered (SSR) using a declarative component tree. Each page declares a name, a path, optional SEO meta, and a components array of nested components. Pages render your tables' records, host forms that write to them, embed interactive islands, and expose public-facing content — all from configuration, no custom React required.

A page needs at minimum a name and a path. Everything else — metadata, access control, scripts, dynamic collection routes, markdown content, view transitions, and per-page toasts — is optional and layered on top.

pages:
  - name: Home
    path: /
    meta:
      title: Welcome
      description: The fastest way to ship internal tools.
    components:
      - type: hero
        content: Build apps from config
      - type: container
        children:
          - { type: text, content: 'Get started in minutes.' }

Page Properties

Each entry in the pages array accepts the following properties.

Property Description
id Optional unique identifier for the page. Auto-generated when omitted.
name Human-readable page name (used in navigation and admin listings).
path URL route. Static (/about), root (/), or dynamic with a :param segment (/blog/:slug). See Routing.
meta SEO and document-head metadata: title, description, Open Graph, Twitter cards, favicons, structured data. See SEO & Metadata.
components Array of component definitions forming the page's render tree. See the component model.
access Access control: 'all' (public), 'authenticated', a role array ['admin'], or { require, redirectTo }. Defaults to 'all'.
collection Template configuration that generates one route per table record (dynamic pages). See Collection Pages.
markdown Render the entire page body from a markdown file or inline string, with layout and table-of-contents options. See Markdown Pages.
source File-based content source (source.file) for a content component — loads markdown from disk with frontmatter. Mutually exclusive with content.
layout Named layout sections (e.g. a data-bound sidebar) wrapping the page body. See Layouts & Sidebars.
scripts Client-side scripts, feature flags, external dependencies, and config data injected into the page. See Interactivity & Scripts.
vars Page-scoped variables (key/value pairs) referenceable via $vars.* in component templates.
toasts Page-level toast notification config (position, default duration).
viewTransition Page navigation animation: fade, slide (with direction), or none, plus duration.
sitemap Per-page sitemap entry (priority, change frequency) or false to exclude the page from the sitemap.
rss Enable an RSS feed for a collection page — true for defaults, or { limit } to cap item count.
pages:
  - name: About
    path: /about
    access: all
    meta: { title: 'About Us' }
    viewTransition: { type: fade, duration: 200 }
    components:
      - { type: text, tag: h1, content: 'About' }

Routing

The path property declares the URL where a page is served.

Path form Example Description
Root / The home page.
Static /about A fixed route.
Nested static /checkout Any number of static segments.
Dynamic /blog/:slug A :param segment captures a value available to the page as a route param.
Record id /tasks/$id Dynamic detail routes resolve the matching record into $record.*.

Dynamic routes are most often paired with a collection block so one page definition generates a route per record. See Collection Pages.

The Component Model

A page's components array is a tree. Every component has a type (one of ~80 built-in component types) and a set of properties. Components compose through a shared module system, so the same cross-cutting properties are available almost everywhere:

Shared property Available on Description
props Almost all components Key-value bag of styling/config attributes rendered as HTML attributes (e.g. className, variant).
content Content/layout components Inline text or markdown; supports $record.*, $vars.*, and key (translation) substitution.
children Container-like components Nested child component definitions.
dataSource Data-bound components Binds the component to a table (filter, sort, pagination, single/search mode). See Data Binding.
visibility Most components Conditional display based on auth state — server-rendered, hidden client-side when conditions are unmet.
responsive Most components Per-breakpoint overrides for responsive behavior.
interactions Interactive components Click actions, hover effects, and entrance animations. See Interactivity & Scripts.
action Form/button components Behavior to run on interaction — crud, auth, navigate, automation, with onSuccess/onError handlers.
i18n Content components Localized content variants per language.

Components are grouped into categories, each documented on its own page:

Category Examples
Layout hero, container, flex, grid, responsiveGrid, card, sidebar, modal, tab-panel
Content text, code, toc, accordion, blockquote, alert, custom-html
Data data-table, list, gallery, kanban, calendar, chart, kpi, timeline
Form Controls input, textarea, select, checkbox, radio, switch, slider, date-picker, file-upload, number-input
Overlays dialog, drawer, popover, tooltip, hover-card, alert-dialog, toast, progress, skeleton
Navigation navigation-menu, dropdown-menu, breadcrumb, tabs, pagination, toggle, button-group, menubar
Media image, icon, video, audio, iframe, carousel, aspect-ratio
Display static-table, command, empty-state, resizable, scroll-area, speech-bubble, status-indicator
Feedback progress, spinner, skeleton
Interactive button, link, alert, badge, button-group
Specialty wizard, reorderable-list, language-switcher, comments, ai-chat
Social comments, commentCount, ai-chat, sharing
SEO & Metadata title, description, Open Graph, Twitter cards, JSON-LD, favicons
Interactivity & Scripts scripts, interactions, auto-save, custom-html

Data Binding

Bind any data component (or container) to a table with dataSource. The bound records expose their fields to descendants through $record.<field> references.

dataSource property Description
table Table name to bind to (validated against app.tables).
fields Specific fields to fetch (omit to fetch all).
filter Array of { field, operator, value } conditions combined with AND. Operators: eq, neq, contains, gt, lt, gte, lte.
sort Array of { field, direction } rules applied in order (primary, secondary).
pagination { pageSize, style }style: numbered renders page navigation; style: loadMore renders a Load More button.
mode single resolves one record by a route param; search filters across searchFields with debounce and maxResults.
id Identifier for cross-component data-source references.
- type: data-table
  dataSource:
    table: tasks
    filter:
      - { field: status, operator: neq, value: archived }
    sort:
      - { field: created_at, direction: desc }
    pagination: { pageSize: 25, style: numbered }

Collection Pages

A collection block turns one page definition into a route per table record. The page's path must include a dynamic :param segment matching slugField.

collection property Description
table Table name to generate collection pages from (must exist in app.tables).
slugField Field whose value becomes the URL parameter (e.g. slug, id).
filter Optional { field, operator, value } conditions limiting which records generate pages.
pages:
  - name: Blog Post
    path: /blog/:slug
    collection:
      table: posts
      slugField: slug
      filter:
        - { field: published, operator: eq, value: true }
    rss: { limit: 20 }
    components:
      - { type: text, tag: h1, content: '$record.title' }
      - { type: text, content: '$record.body', props: { format: markdown } }

A request to /blog/123 that does not match any record returns a 404.

Markdown Pages

Render a whole page from markdown — either inline or from a file — with frontmatter, layout, and an auto-generated table of contents.

markdown property Description
content Inline markdown string.
file Path to a markdown file (e.g. content/docs.md), resolved from project root. Mutually exclusive with content.
layout Wrapper style: prose (default), docs, full, or none.
toc Table-of-contents config — true for defaults, or { maxDepth, position } (inline or sidebar).

YAML frontmatter (between --- delimiters) is parsed and exposed as $frontmatter.* in meta and sibling properties. Markdown HTML is sanitized to prevent XSS (consistent with the text/alert content components).

pages:
  - name: Docs Home
    path: /docs
    markdown:
      file: content/docs/home.md
      layout: docs
      toc: { maxDepth: 3, position: sidebar }

For the contentDir collection (one page per markdown file in a directory, with a derived sidebar), use a content component with a contentDir source:

contentDir property Description
directory Directory containing markdown content files.
slugFrom Derive URL slug from filename or filepath.
include Glob pattern to filter files (e.g. *.md).
sort { field, order } — sort by a frontmatter field (e.g. date, desc).
filter Filter conditions on frontmatter fields.
nav Sidebar config derived from the collection: { enabled, groupBy, labelFrom }.

Layouts & Sidebars

The layout property wraps the page body in named sections. The most common is a data-bound sidebar rendered inside the page <aside>.

Sidebar section property Description
dataSource Binds entries to a table with { table, filter, sort }.
label Per-record label expression (supports $record.<field>).
href Per-record anchor href (supports $record.<field>).
archivedField Field whose truthy value hides an entry from the sidebar.
activeIndicator Highlights the entry matching the active scope (e.g. tenant-switcher cookie).

A scoped sidebar bound to $currentUser.assignments.<table> renders one entry per assigned record; a global admin (isUnrestricted=true) sees all records.

Access Control

The access property gates a page:

Form Meaning
'all' Everyone, including unauthenticated visitors (default).
'authenticated' Any logged-in user.
['admin', 'editor'] Specific role names.
{ require: 'authenticated', redirectTo: '/login' } Redirect unauthorized users instead of returning an error.