BlockBite docs

Island folders

Organise sections as families and variants, declare their fields and type their components.

An island is a section of a page that editors can fill in. It is an ordinary Astro component plus a fields.yaml file that declares which values it accepts. This guide describes the current @blockbite/astro implementation.

Families and variants

Islands are grouped in two folder levels under src/islands/:

src/islands/
  hero/                     family
    simple/                 variant
      Island.astro
      fields.yaml
  editorial-grid/           family
    namespace.json
    three-up/               variant
      Island.astro
      fields.yaml
    swipeable-row/          variant
      Island.astro
      fields.yaml
  • A family is one kind of section, such as a hero or an editorial grid.
  • A variant is one design of that section. Content refers to it by its path, family/variant, for example editorial-grid/three-up.
  • Folder names use lowercase letters, digits and -.
  • A folder becomes an island only when it contains a fields.yaml. Other folders, such as shared components, are left alone.

Declare the fields

fields.yaml lists the variant’s editable fields. Each key is the field’s identity and also the name of the component prop:

# src/islands/editorial-grid/three-up/fields.yaml
version: 1
fields:
  eyebrow:
    type: string
    label: Eyebrow
  title:
    type: string
    label: Title
  entries:
    type: repeater
    label: Entries
    fields:
      title:
        type: string
        label: Title
      meta:
        type: string
        label: Meta
  • Every field has a type and a label. The label is the editor-facing name.
  • string holds plain text. link holds one URL, image an image location, and svg an approved library key. repeater holds a list of rows containing scalar fields; rows cannot contain another repeater.
  • markdown holds inline formatted text with links. It stays a Markdown string in your JSON content and needs the native inline component shown below.
  • heading-tag holds an h1–h6 value separately from the heading’s text. See the field reference for binding rules.
  • Fields appear in the order they are written.
  • The file contains no IDs. Renaming a key renames the field: update the component and the page content in the same change.

Variants of one family can use the same keys. three-up and swipeable-row both declare title and entries, so the same values fit both designs.

For an introduction with inline links, explicitly declare the field:

intro:
  type: markdown
  label: Introduction

Then consume it inside your existing paragraph:

---
import MarkdownInline from '@blockbite/astro/markdown-inline';
const { intro } = Astro.props;
---
<p><MarkdownInline text={intro} /></p>

For example, Explore [our neighborhoods](/neighborhoods/) becomes an actual link. Bold, italic and inline code also work. This field supports one paragraph; use native Markdown articles for full documents. Plain string fields keep their existing behavior. Markdown fields are currently for native Astro sites; CMS exporters report them as unsupported before writing a package.

Type the component

Island.astro is a normal Astro component. It names its own path and receives exactly the props its fields.yaml declares:

---
import type { IslandProps } from '@blockbite/astro/islands';
type Props = IslandProps<'editorial-grid/three-up'>;
const { eyebrow, title, entries } = Astro.props;
---
<section class="editorial-grid three-up">
  {eyebrow && <p class="eyebrow">{eyebrow}</p>}
  <h2>{title}</h2>
  <ul>
    {entries.map((entry) => <li><h3>{entry.title}</h3><p>{entry.meta}</p></li>)}
  </ul>
</section>

You do not write these types yourself. The blockbite() integration generates them from every fields.yaml into Astro’s .astro/ folder, which is not part of your source. astro check then reports a component that uses a field its fields.yaml does not declare.

To enable the integration, add it to astro.config.mjs:

import { defineConfig } from 'astro/config';
import blockbite from '@blockbite/astro';

export default defineConfig({
  integrations: [blockbite()],
});

Static and published islands

A family without namespace.json is used only by the site itself and needs no IDs. Add a namespace.json when a family’s variants are published to a CMS. It holds the only generated IDs in a project: one for the family and one per published variant.

{
  "version": 1,
  "templateId": "tpl-ri27rkqrgxvq",
  "name": "Editorial grid",
  "defaultVariant": "three-up",
  "variants": {
    "three-up": "48qqztws0rcl",
    "swipeable-row": "m1pdrqtpj3ge"
  }
}

The IDs live in the family file, not in the variant folders, so copying a variant folder never copies its identity. Do not write these IDs by hand. Tooling to create them, and publishing itself, are planned.

When something is wrong

The integration checks island folders when Astro starts and reports problems with the file and field key. Correct the named declaration, component prop or content value, then run the project’s checks again.

astro dev watches changes to existing declarations and newly added island field or namespace files. After changing fields, run npx astro sync --force to revalidate cached page content.

See the island file reference for every rule and limit, and page content for using islands on a page.