The Basics
Block’s source code is a TypeScript file with a default-exported React component:shadcn/ui
shadcn/ui components are already pre-configured and follow your app’s theme out of the box. They’re available under the@/components/ui path, so you can import them like this:
accordion, alert, alert-dialog, aspect-ratio, avatar, badge, button, calendar, card, carousel, chart, checkbox, collapsible, command, context-menu, dialog, drawer, dropdown-menu, empty, hover-card, input, input-group, input-otp, item, kbd, label, menubar, native-select, navigation-menu, pagination, popover, progress, radio-group, resizable, scroll-area, select, separator, sheet, skeleton, slider, sonner, spinner, switch, table, tabs, textarea, toggle, toggle-group, tooltip
Check out the shadcn/ui docs for usage details and examples for each component.
Icons
Preferred icon pack is Lucide Icons, but you can opt for a different one.Styling
We follow the default shadcn/ui naming convention for background/foreground color pairs (e.g.bg-primary / text-primary-foreground) which maps to your app’s theme colors.
By default, block occupies full width of the page but special classes - container and content are available to constrain the width of content to match app’s max width settings to ensure visual consistency with other blocks:
Data from Your Datasource
Import data hooks from@/lib/datasource. Use these when you want to display records from your connected data source. All data fetching hooks follow a query builder pattern so you can be quite expressive with your queries.
Defining a select query
Field mappings have to be static, we also use static analysis to determine which fields your block actually uses so we don’t overfetch and don’t accidentally expose potentially sensitive data.useRecords — fetch a list of records
useRecord — fetch a single record by ID
Use with useCurrentRecordId() to display details of the record currently shown in a list/detail context:
Filtering records
Use theq query builder for filters. Filters support up to 2 levels of nesting.
| Builder | Methods |
|---|---|
q.text(field) | is, isNot, contains, startsWith, endsWith, isOneOf, isNoneOf, hasAllOf, isEmpty, isNotEmpty |
q.number(field) | is, isNot, gt, gte, lt, lte, between, isEmpty, isNotEmpty |
q.boolean(field) | is, isNot, isEmpty, isNotEmpty |
q.date(field) | is, isNot, gt, gte, lt, lte, between, isNotBetween, isEmpty, isNotEmpty |
q.array(field) | is, isOneOf, isNoneOf, hasAllOf, isEmpty, isNotEmpty |
q.and(...) | combine filters with AND |
q.or(...) | combine filters with OR |
Sorting records
useLinkedRecords — fetch options from a linked table
Use for dropdowns, comboboxes, or tag pickers where you need to show values from a related table:
Mutating Records
All mutation hooks expose anenabled boolean — always check it before rendering the mutation UI or calling the function. It reflects whether the current user has sufficient permissions. If called without checking enabled, the mutation will throw an error.
useRecordCreate
useRecordUpdate
useRecordDelete
Uploading Files
UseuseUpload from @/lib/datasource to upload files and get back a URL to store in a record.
Current User
Get info about the logged-in user withuseCurrentUser from @/lib/user. Returns null if no user is logged in.
id:string | null(only present when user sync is enabled)fullName:string | nullemail:string | nullavatar:string | null
Metrics & Charts
useMetric — single aggregated value
Useful for KPI cards (total sales, average rating, etc.):
metric.sum(field), metric.avg(field), metric.max(field), metric.min(field), metric.distinct(field), metric.count()
useChartData — grouped data for charts
| Bucket | Format example |
|---|---|
metric.bucket.year | 2025 |
metric.bucket.month.iso | "2025-03" |
metric.bucket.month.long | "March 2025" |
metric.bucket.day.iso | "2025-03-15" |
metric.bucket.day.long | "Mar 15, 2025" |
Editable Settings
Editable settings let builders modify block content through the editor UI (Content → Settings tab) without touching code. Always use them for any text, images, icons, or lists that might change between block instances. Import from@/lib/editable-settings.
useTextSetting
Returns a string. Use for titles, descriptions, button labels, URLs, etc.
useImageSetting
Returns { src: string; alt: string }.
useVideoSetting
Returns { src: string }.
useVibeCodingBlockIconSetting
Returns { icon: string } where icon is a lucide-react icon name. Render it with the DynamicIcon component.
useNavigationSetting
Returns { action: "OPEN_URL" | "OPEN_PAGE"; destination: string; openIn: "SELF" | "TAB" } | { action: "OPEN_CHAT" }.
useArraySetting
Returns an array of items with a consistent shape. Use for feature lists, team members, FAQs, testimonials, etc.
useBooleanSetting
Returns a boolean. Use for toggles, switches, show/hide elements, etc.
"text", "image", "video", "vibeCodingBlockIcon"
Constraints:
- Schema cannot contain nested arrays — for list-like text, use a
"text"field with a separator (e.g. comma) and split it in code - Do not put a
vibeCodingBlockIconfield as the first field in the schema - Calling two settings hooks with the same
nameis not allowed
Complete Example — Feature Showcase
A full-featured block combining editable settings, datasource records, and shadcn/ui:Fetching field options
UseuseFieldOptions to fetch available options for SELECT or multi-select fields. This is useful for building filters, dropdowns, badges, or any UI that needs to display the available choices from the datasource without hardcoding them.
Example to build a filter UI using useFieldOptions: