
guide
Create a new section without code
Blog, Gallery and Projects are all collections. Editors can add new ones, such as Services or Team, straight from the Studio.
AM
Ada Morgan
Editor
Leo Hart
Frontend Engineer

Blocks live in two places: a schema in the Studio and a component in the Nuxt app. TypeScript keeps them in sync.
apps/studio/schemaTypes/blocks/ and register it in schemaTypes/index.ts and objects/page-builder.ts.pnpm typegen to regenerate the types used by the frontend.Block<Name>.vue in apps/web/app/components/blocks/ with a block: BlockOf<'name'> prop.PageBlocks.vue.A schema, a component and one line in the registry. Switch between the files with the tabs.
import { defineArrayMember, defineField, defineType } from 'sanity' export const stats = defineType({ name: 'stats', title: 'Stats', type: 'object', fields: [ defineField({ name: 'title', type: 'string' }), defineField({ name: 'items', type: 'array', of: [defineArrayMember({ type: 'object', fields: [ defineField({ name: 'value', type: 'string' }), defineField({ name: 'label', type: 'string' }) ] })] }) ]})<script setup lang="ts">import type { BlockOf } from '~/types/sanity' defineProps<{ block: BlockOf<'stats'>, index: number }>()</script> <template> <UPageSection :title="block.title"> <UPageGrid> <UPageCard v-for="item in block.items" :key="item._key" :title="item.value" :description="item.label" /> </UPageGrid> </UPageSection></template>const registry: Record<BlockType, Component> = { hero: LazyBlockHero, // … stats: LazyBlockStats}Keep field names identical to the Nuxt UI props. The component can then pass values straight through, and the next developer can look up a field in the Nuxt UI docs.

Ada Morgan
Editor

Ada Morgan
Editor
