/studio-ui-patterns
Design system UI patterns for Supabase Studio. Use when building or updating
$ npx -y skills add supabase/supabase --skill studio-ui-patterns --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/studio-ui-patterns
Context preview
The summary Claude sees to decide when to auto-load this skill.
Design system UI patterns for Supabase Studio. Use when building or updating
SKILL.md
studio-ui-patterns.SKILL.mdname: studio-ui-patterns
description: Design system UI patterns for Supabase Studio. Use when building or updating
pages, forms, tables, charts, empty states, navigation, cards, alerts, or side panels
(sheets). Covers layout selection, component choice, and placement conventions.
Studio UI Patterns
The Design System docs and demos are the source of truth. Always check the relevant demo file before composing new UI.
Layout
Docs: `apps/design-system/content/docs/ui-patterns/layout.mdx`
Build pages with `PageContainer`, `PageHeader`, and `PageSection`.
| Content type | `size` | | ----------------- | ----------- | | Settings / config | `"default"` | | Lists / tables | `"large"` | | Full-screen views | `"full"` |
- If filters/search exist on a list page, align table actions with the filters (don't use `PageHeaderAside`/`PageSectionAside` for those actions)
- If no filters, actions can go in `PageHeaderAside` or `PageSectionAside`
Demos: `page-layout-settings.tsx`, `page-layout-list.tsx`, `page-layout-list-simple.tsx`, `page-layout-detail.tsx` (all in `apps/design-system/registry/default/example/`)
Forms
Docs: `apps/design-system/content/docs/ui-patterns/forms.mdx`
- Use `react-hook-form` + `zod`
- Use `FormItemLayout` instead of manually composing `FormItem`/`FormLabel`/`FormMessage`/`FormDescription`
- Wrap inputs with `FormControl`; import primitives from `ui`
Layout selection:
| Context | Layout | Container | | ------------------------------------------ | ------------------------------------------ | ---------------------------------------------------------- | | Page (settings/config) | `FormItemLayout layout="flex-row-reverse"` | `Card` (`CardContent` per field; `CardFooter` for actions) | | Side panel — wide | `FormItemLayout layout="horizontal"` | `SheetSection` | | Side panel — narrow (`size="sm"` or below) | `FormItemLayout layout="vertical"` | `SheetSection` |
Dirty state / submit:
- Destructure `isDirty` from `form.formState` to show Cancel and disable Save
- Show loading on submit button via `loading` prop
- If submit button is outside `<form>`, set a stable `formId` and use `form` prop on the button
Demos: `form-patterns-pagelayout.tsx`, `form-patterns-sidepanel.tsx`
Tables
Docs: `apps/design-system/content/docs/ui-patterns/tables.mdx`
| Pattern | Use when | | ---------- | ----------------------------------------------------------------------- | | `Table` | Simple, static, semantic display | | Data Table | TanStack-powered; sorting, filtering, pagination; composed per use-case | | Data Grid | Virtualization, column resizing, or complex cell editing |
- Actions: above the table, aligned right
- Search/filters: above the table, aligned left
- If table is primary content with no filters, actions can live in the page's primary/secondary actions area
Demos: `table-demo.tsx`, `data-table-demo.tsx`, `data-grid-demo.tsx`
Charts
Docs: `apps/design-system/content/docs/ui-patterns/charts.mdx`
- Use provided chart building blocks; avoid passing raw Recharts components to `ChartContent`
- Use `useChart` context flags for loading/disabled states
- Keep composition straightforward — avoid over-abstraction
Demos (in `apps/design-system/__registry__/default/block/`): `chart-composed-demo.tsx`, `chart-composed-basic.tsx`, `chart-composed-states.tsx`, `chart-composed-metrics.tsx`, `chart-composed-actions.tsx`, `chart-composed-table.tsx`
Empty States
Docs: `apps/design-system/content/docs/ui-patterns/empty-states.mdx`
| Scenario | Pattern | | ------------------------ | ------------------------------------------------------------------- | | Initial / onboarding | Presentational empty state with value prop + clear next action | | Data-heavy lists | Informational empty state matching the list/table layout | | Zero results from search | Keep layout consistent with data state to avoid jarring transitions | | Missing route | Centered `Admonition` |
Demos: `empty-state-presentational-icon.tsx`, `empty-state-initial-state-informational.tsx`, `empty-state-zero-items-table.tsx`, `data-grid-empty-state.tsx`, `empty-state-missing-route.tsx`
Navigation
Docs: `apps/design-system/content/docs/ui-patterns/navigation.mdx`
- Use `NavMenu` for a horizontal list of related views within a consistent page layout
- Activating an item must trigger a **URL change** — no local-only tab state
Cards
- Group related information in cards
- `CardContent` for sections, `CardFooter` for actions
- Only use `CardHeader`/`CardTitle` when context isn't already provided by surrounding content
- Use headers/titles when multiple cards represent distinct groups (e.g. multiple settings sections)
Alerts
- Use `Admonition` to call out important actions, restrictions, or critical context
- Place at the **top of a page's content** (below page title) or **top of the relevant section** (below section title)
- Use sparingly
Sheets (Side Panels)
Use a `Sheet` when switching pages would be disruptive and the user needs to maintain context (e.g. selecting a row from a list to edit).
Structure:
- `SheetContent` with `size="lg"` for forms needing horizontal layout
- Use `SheetHeader`, `SheetTitle`, `SheetSection`, `SheetFooter`
- Submit/cancel actions go in `SheetFooter`
Forms in sheets:
- `layout="horizontal"` for wider sheets
- `layout="vertical"` for narrow sheets (`size="sm"` or below)
- When the sheet contain
Read more
name: studio-ui-patterns description: Design system UI patterns for Supabase Studio. Use when building or updating pages, forms, tables, charts, empty states, navigation, cards, alerts, or side panels (sheets). Covers layout selection, component choice, and placement conventions.
Studio UI Patterns
The Design System docs and demos are the source of truth. Always check the relevant demo file before composing new UI.
Layout
Docs: `apps/design-system/content/docs/ui-patterns/layout.mdx`
Build pages with `PageContainer`, `PageHeader`, and `PageSection`.
| Content type | `size` | | ----------------- | ----------- | | Settings / config | `"default"` | | Lists / tables | `"large"` | | Full-screen views | `"full"` |
- If filters/search exist on a list page, align table actions with the filters (don't use `PageHeaderAside`/`PageSectionAside` for those actions)
- If no filters, actions can go in `PageHeaderAside` or `PageSectionAside`
Demos: `page-layout-settings.tsx`, `page-layout-list.tsx`, `page-layout-list-simple.tsx`, `page-layout-detail.tsx` (all in `apps/design-system/registry/default/example/`)
Forms
Docs: `apps/design-system/content/docs/ui-patterns/forms.mdx`
- Use `react-hook-form` + `zod`
- Use `FormItemLayout` instead of manually composing `FormItem`/`FormLabel`/`FormMessage`/`FormDescription`
- Wrap inputs with `FormControl`; import primitives from `ui`
Layout selection:
| Context | Layout | Container | | ------------------------------------------ | ------------------------------------------ | ---------------------------------------------------------- | | Page (settings/config) | `FormItemLayout layout="flex-row-reverse"` | `Card` (`CardContent` per field; `CardFooter` for actions) | | Side panel — wide | `FormItemLayout layout="horizontal"` | `SheetSection` | | Side panel — narrow (`size="sm"` or below) | `FormItemLayout layout="vertical"` | `SheetSection` |
Dirty state / submit:
- Destructure `isDirty` from `form.formState` to show Cancel and disable Save
- Show loading on submit button via `loading` prop
- If submit button is outside `<form>`, set a stable `formId` and use `form` prop on the button
Demos: `form-patterns-pagelayout.tsx`, `form-patterns-sidepanel.tsx`
Tables
Docs: `apps/design-system/content/docs/ui-patterns/tables.mdx`
| Pattern | Use when | | ---------- | ----------------------------------------------------------------------- | | `Table` | Simple, static, semantic display | | Data Table | TanStack-powered; sorting, filtering, pagination; composed per use-case | | Data Grid | Virtualization, column resizing, or complex cell editing |
- Actions: above the table, aligned right
- Search/filters: above the table, aligned left
- If table is primary content with no filters, actions can live in the page's primary/secondary actions area
Demos: `table-demo.tsx`, `data-table-demo.tsx`, `data-grid-demo.tsx`
Charts
Docs: `apps/design-system/content/docs/ui-patterns/charts.mdx`
- Use provided chart building blocks; avoid passing raw Recharts components to `ChartContent`
- Use `useChart` context flags for loading/disabled states
- Keep composition straightforward — avoid over-abstraction
Demos (in `apps/design-system/__registry__/default/block/`): `chart-composed-demo.tsx`, `chart-composed-basic.tsx`, `chart-composed-states.tsx`, `chart-composed-metrics.tsx`, `chart-composed-actions.tsx`, `chart-composed-table.tsx`
Empty States
Docs: `apps/design-system/content/docs/ui-patterns/empty-states.mdx`
| Scenario | Pattern | | ------------------------ | ------------------------------------------------------------------- | | Initial / onboarding | Presentational empty state with value prop + clear next action | | Data-heavy lists | Informational empty state matching the list/table layout | | Zero results from search | Keep layout consistent with data state to avoid jarring transitions | | Missing route | Centered `Admonition` |
Demos: `empty-state-presentational-icon.tsx`, `empty-state-initial-state-informational.tsx`, `empty-state-zero-items-table.tsx`, `data-grid-empty-state.tsx`, `empty-state-missing-route.tsx`
Navigation
Docs: `apps/design-system/content/docs/ui-patterns/navigation.mdx`
- Use `NavMenu` for a horizontal list of related views within a consistent page layout
- Activating an item must trigger a **URL change** — no local-only tab state
Cards
- Group related information in cards
- `CardContent` for sections, `CardFooter` for actions
- Only use `CardHeader`/`CardTitle` when context isn't already provided by surrounding content
- Use headers/titles when multiple cards represent distinct groups (e.g. multiple settings sections)
Alerts
- Use `Admonition` to call out important actions, restrictions, or critical context
- Place at the **top of a page's content** (below page title) or **top of the relevant section** (below section title)
- Use sparingly
Sheets (Side Panels)
Use a `Sheet` when switching pages would be disruptive and the user needs to maintain context (e.g. selecting a row from a list to edit).
Structure:
- `SheetContent` with `size="lg"` for forms needing horizontal layout
- Use `SheetHeader`, `SheetTitle`, `SheetSection`, `SheetFooter`
- Submit/cancel actions go in `SheetFooter`
Forms in sheets:
- `layout="horizontal"` for wider sheets
- `layout="vertical"` for narrow sheets (`size="sm"` or below)
- When the sheet contain
Supabase is the Postgres development platform. We're building the features of Firebase using enterprise-grade open source tools. [x] Hosted Postgres Database. Docs [x] Authentication and Authorization. Docs [x] Auto-generated APIs. [x] REST. Docs [x] GraphQL.
Repo: supabase/supabase
Other skills on supabase.
- /clickhouse-logs-queries
Write, review, and migrate Supabase logs queries against the ClickHouse-backed `logs` table (the `logs.all.otel` analytics endpoint). Use this whenever a task involves Logs Explorer SQL, the `log_attributes` map, querying a log `source` (edge_logs, postgres_logs, auth_logs,
Open skill - /copywriting
Write or audit UI copy (buttons, labels, empty states, error messages, tooltips, form text) anywhere in the monorepo. Load it before shipping or reviewing any user-facing text — including when copy is incidental to the task, like a new feature that adds buttons, toasts, dialogs,
Open skill - /dev-toolbar-review
Safety rules for the dev toolbar, PostHog client, and feature flags. Use
Open skill - /docs-content
Write, edit, organize, and review Supabase content anywhere in apps/docs — guides, explainers, tutorials, troubleshooting entries, reference docs, and partials. Use for MDX/TOML authoring, frontmatter, navigation, terminology, links, code samples, content listings, and docs
Open skill - /react-hook-form
Correct React Hook Form usage anywhere in the monorepo — data flow, subscriptions,
Open skill - /safe-sql-execution
Use whenever code will build, return, fetch, or execute SQL that runs against a user's real Postgres database — even when the request reads like an ordinary feature or bug fix and never says "security," "injection," or "SafeSqlFragment." This covers: writing or editing any
Open skill

