Making component pages editable
Many Astro themes build their main pages — home, services, pricing, about — from
components, with the words written straight into the .astro file:
<Hero tagline="Free & open source" title="Websites that load fast" actions={[{ text: 'Get started', href: '/start', variant: 'primary' }]}/>Orbit edits content, not code, so those words aren’t editable as they stand.
Orbit won’t rewrite your .astro files for you — every theme is different, and
changing a page’s code is a developer’s call. Instead, move the words into a content
entry and let the page read them. The design stays in code; the words become a form.
That’s the whole of making a component page Orbitable.
1. Describe the page’s words in your content config
Section titled “1. Describe the page’s words in your content config”Add a collection for the page, with one field per piece of text. Keep the fields
in content.config.ts itself — Orbit reads that file but doesn’t follow imports
from your own modules, so a schema imported from elsewhere would show no fields.
const text = z.string().optional();const action = z.object({ text: z.string(), href: z.string(), variant: z.enum(['primary', 'secondary']).optional(),});
const homePage = defineCollection({ loader: glob({ pattern: 'home.md', base: 'src/content/pages' }), schema: z.object({ hero: z.object({ tagline: text, title: text, actions: z.array(action).optional() }).optional(), features: z .object({ title: text, items: z.array(z.object({ title: text, description: text })).optional(), }) .optional(), }),});
export const collections = { /* …your other collections… */ home: homePage };A pattern naming a single file (home.md) makes it a fixed page: editors can
change it but not add more.
2. Put the words in the entry
Section titled “2. Put the words in the entry”---hero: tagline: Free & open source title: Websites that load fast actions: - text: Get started href: /start variant: primaryfeatures: title: What you get items: - title: Fast description: Pages that load in a blink.---3. Have the page read the entry
Section titled “3. Have the page read the entry”---import { getEntry } from 'astro:content';import Hero from '~/components/widgets/Hero.astro';import Features from '~/components/widgets/Features.astro';
const page = (await getEntry('home', 'home'))!.data;---
<Layout> {page.hero && <Hero {...page.hero} />} {page.features && <Features id="features" {...page.features} />}</Layout>The components are unchanged: they get the same props as before, just from the entry instead of the code.
4. Tell Orbit it’s a form-only page
Section titled “4. Tell Orbit it’s a form-only page”collections: home: canAdd: false # one fixed page bodyless: true # no text editor — every word is a fieldWhat to keep in code
Section titled “What to keep in code”Anything that’s design rather than words stays in the .astro page:
- layout and order of sections, and which ones appear;
- CSS classes, colours, backgrounds, spacing and animation settings;
- decorative extras (a divider, a trailing icon).
If a title mixes words and styling — say one highlighted phrase — split it into two
fields (title and titleAccent) and add the styling in the page, so editors never
see class names.
Text fields can still take simple HTML (<strong>, <code>, <br>) if your
components render them as HTML.
A worked example
Section titled “A worked example”The AstroWind business site in Orbit Extras
is converted this way: the words of its home, about, services, pricing and contact
pages — heroes, features, team, testimonials, prices, FAQs and the rest — are forms in
Orbit, while its design is untouched. A small helper reads each page’s entry, and a
shared page() function in content.config.ts keeps the five schemas short.