`)
→ [Text editing](../visual-editing-reference.md#text-editing)
- [ ] **Component prop contract**: Registered components accept spread props matching the shape of their `data-prop` value — not a named wrapper prop
→ [Component prop contract](../visual-editing-reference.md#component-prop-contract)
- [ ] **Cross-collection editable guard**: Shared components used for both frontmatter items and programmatic cross-collection content have an `editable` prop to conditionally strip editable attributes
→ [Array editing](../visual-editing-reference.md#array-editing)
- [ ] **`` blueprints**: Primitive-only arrays that can be empty at build time have `` children.
→ [Array editing](../visual-editing-reference.md#array-editing)
- [ ] **Data file input config**: Every data file in `data_config` has a `file_config` entry with proper input types and structure references
→ [configuration.md](../../cloudcannon-configuration/astro/configuration.md)
### Page builder only (skip if not applicable)
- [ ] **Array wrapper attributes**: `data-component-key="_type"` alongside `data-editable="array"` and `data-prop="content_blocks"`. `data-id-key` can be omitted when it matches `data-component-key`
→ [Page builder blocks](../visual-editing-reference.md#page-builder-blocks)
- [ ] **Block items**: Both `data-editable="array-item"` and `data-component={_type}` on each block element
→ [Page builder blocks](../visual-editing-reference.md#page-builder-blocks)
- [ ] **Widget nested editables**: Widget components have text/image regions on their key fields
→ [Page builder blocks](../visual-editing-reference.md#page-builder-blocks)
- [ ] **Sub-arrays in widgets**: Widget arrays (`items`, `actions`, `steps`) have `data-editable="array"` + `data-prop` on the container and `data-editable="array-item"` on each item
→ [Sub-arrays within widget components](../visual-editing-reference.md#sub-arrays-within-widget-components)
- [ ] **UI component variants**: All numbered variants of shared components have editable attributes
→ [Sub-arrays within widget components](../visual-editing-reference.md#sub-arrays-within-widget-components)
- [ ] **Shared component map**: `src/cloudcannon/componentMap.ts` exists and both `BlockRenderer.astro` and `registerComponents.ts` import from it
→ [Component re-rendering](visual-editing-reference.md#astro-components)
- [ ] **Registration keys match `_type`**: Every key uses the exact `_type` string from content files
→ [Page builder blocks](../visual-editing-reference.md#page-builder-blocks)
- [ ] **All block types registered**: Every `_type` value in content files has a `componentMap` entry
→ [Page builder blocks](../visual-editing-reference.md#page-builder-blocks)
- [ ] **Build output verification**: `dist/` contains `data-component-key`, `data-component=`, and `data-editable="array-item"` attributes (grep to verify)
## Pre-handoff sweep
Before declaring the migration complete, run these three verifications. This is the net that catches shared sections that slipped through the section census and completeness checklist.
- [ ] **Census walk-through.** Re-open `.cloudcannon/migration/visual-editing.md` and walk every census row. Each row's treatment is implemented in the repo — not just proposed. Rows with `sidebar-only` justification are written out with a technical reason.
- [ ] **Shared-UI table walk-through.** Open [../../migrate-to-cloudcannon/astro/cc-friendly-conventions.md § Shared-UI treatment table](../../migrate-to-cloudcannon/astro/cc-friendly-conventions.md#shared-ui-treatment-table) and verify every row against the repo: the named data file exists in `src/data/`, is wired in `data_config` with a `file_config` entry, the component reads from the data file, and editables are in place. If a row doesn't apply (the site has no footer, no CTA, etc.), note it explicitly in `.cloudcannon/migration/visual-editing.md`.
- [ ] **Build grep.** Run `grep -rE "data-editable|data-prop" dist/` and confirm matches for every shared section name you expect: footer, cta, share, author, any other shared partials. If a name is missing, the section wasn't wired up.
Use grep counts, not line counts (`grep -oE`, not `grep -c`), when verifying — compressed HTML puts everything on one line, so `grep -c` always returns 1.
## Self-check before handoff
Answer each question. Every "No" is a blocker.
| Check | Cross-link |
| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Every registered-component field-group nested under a single frontmatter key (no `propPrefix=""`)? | [Frontmatter co-location](../visual-editing-reference.md#scattered-fields-feeding-a-registered-component--nest-the-frontmatter) |
| Every content file backfilled after a schema default changed? | [L24 — schema defaults vs backfill](../troubleshooting.md#values-that-do-not-update) |
| Every multiselect/select backed by a data file uses `values: data.*`? | [L3/L25 — data-backed selects](../../cloudcannon-configuration/SKILL.md#common-mistakes) |
| Every standalone-placed registered component wrapped with `