Building a theme
Blueprints and fields
The form an editor fills in, and every fieldtype you can put on it.
A blueprint is two things at once: the form an editor fills in, and the shape the stored data is checked against. Writing one is the closest thing in Nibble to designing a page.
# schema/blueprints/collections/guides/guide.yml
schema: 1
title: Guide
tabs:
main:
display: Content
sections:
- fields:
- handle: body
field:
type: rich_text
display: Body
localizable: true
- handle: region
field:
type: terms
taxonomies: [regions]
max_items: 1
seo:
display: SEO
sections:
- fields:
- import: nibble::seo
Tabs group the form. Sections group fields within a tab, and can carry an instruction line. Fields
each have a handle — the name the data is stored under, which your views use — and a field describing the
type and its options.
Common options on any field: display (its label), instructions (help text under it), required, width
(percentage of the row), localizable, listable (offered as a column in the listing), and read_only.
The fieldtypes
| Group | Types |
|---|---|
| Text | text, textarea, rich_text, markdown, slug, secret |
| Numbers and dates | integer, date |
| Choice | select, radio, checkboxes, toggle, list |
| Relationships | entries, terms, relationship, link |
| Files | assets, files |
| Repeating | grid, replicator |
| Whole-page | seo |
A few worth knowing properly:
rich_text is the full editor: headings, lists, links, images, tables, code blocks with a language picker,
find and replace. It is stored as structured data, not HTML, and rendered to HTML on the server — see
Theme helpers.
markdown is a plain textarea with a Preview button. The preview is rendered by the server, so it shows
exactly what the theme will receive. Turn on sanitize when the text might come from someone you do not trust.
replicator lets an editor build a page from blocks in any order. Each set you define renders through
themes/<yours>/views/sets/<name>.vue, which is how a flexible page is assembled without giving anyone a blank
HTML box.
grid is a simple repeating row of fields — opening hours, a price table.
entries and terms open a picker rather than a text box, and store a reference. If the target moves or is
renamed, the reference still points at it.
Fieldsets: writing a group once
A fieldset is a group of fields imported into several blueprints:
- import: nibble::seo
Nibble ships nibble::seo, nibble::page_fields, nibble::post_fields and nibble::featured_image. Make your
own with bin/rails nibble:generate:fieldset <name>, and import it as <name>.
Change the fieldset and every blueprint using it changes — which is the point, and the reason to reach for one whenever the same three fields appear twice.
Conditional fields
A field can appear only when another has a particular value:
- handle: video_url
field:
type: text
if: { layout: video }
The form hides and shows it as the editor works, and validation follows — a hidden field is not required. The
available keys are if, if_any, unless, unless_any, show_when, show_when_any, hide_when and
hide_when_any; the _any forms pass when any one condition matches rather than all of them.
Generated types
Every blueprint contributes to themes/<yours>/.nibble/types.d.ts, so your views have real TypeScript types for
the fields they render, and an editor that autocompletes them.
It is regenerated by the generators and by bin/rails nibble:schema:types, and bin/rails nibble:check fails if
it is stale — so a blueprint change that was never reflected in the types cannot reach production.