Extensibility
How Agility Decorate automatically tags Next.js components with the data-agility-* attributes Web Studio needs for click-to-edit — and the nested list-item editing fix it uncovered along the way.
Agility Decorate (ag-decor) is a command-line tool that automatically adds the data-agility-* attributes Web Studio needs for live, click-to-edit editing — component outlines, field-level pencils, and instant preview — to an existing Next.js site's component code. It replaces a step that, until now, had to be done by hand: wiring every field of every component with the right attribute, correctly, everywhere it's rendered.
@agility/agility-decorate@agility/nextjsWeb Studio's entire live-editing experience — the dashed component outlines, the pencil that opens a field for editing, the instant preview as you type — depends on the rendered HTML carrying a specific set of attributes:
| Attribute | What it marks |
|---|---|
data-agility-component | The root element of a module, tied to its contentID |
data-agility-field | The element that renders one specific CMS field |
data-agility-nested-listitem | An item rendered from a linked Content List field (see below) |
Without them, Web Studio can still render your site in the preview pane, but it has no way to know which piece of DOM corresponds to which piece of content — so there's no outline, no pencil, and no click-to-edit. Every one of these attributes has traditionally been something a developer types onto their own JSX, field by field, component by component. For an established component library, that's a lot of components to retrofit correctly, and every new one needs the same treatment going forward.
Agility Decorate parses your component source with jscodeshift (an AST-based codemod framework), figures out which JSX element renders which CMS field, and writes the attributes in for you.
getContentItem call, an already-loaded module, or a dynamic page item — without requiring you to restructure anything.fields.x && ...), or passed indirectly through another function — the tool tells them apart and only tags what it's confident about.getContentList(...).items.map((item) => ...) loop gets each of its rendered items decorated independently, with its own contentID scope, distinct from the enclosing component's own fields.data-agility-* attribute stripped from both sides — if anything else changed, it aborts the write for that file. That's what makes it safe to run against a real, unfamiliar codebase rather than a purpose-built demo.# install from npm
npm install -g @agility/agility-decorate
# read-only survey: what's decoratable, what's already tagged, what's ambiguous
ag-decor map --registry components/agility-components/index.ts
# apply the tags
ag-decor apply --registry components/agility-components/index.ts --write
# CI gate: fail the build if anything resolvable is left undecorated
ag-decor check --registry components/agility-components/index.ts
Every command targets the same file passed to your ContentZone's getModule prop — the registry that already maps a module name to its component file — so there's no separate configuration to maintain.
Agility Decorate exists for one reason: so that Web Studio's live-editing experience — the thing that lets a content editor click directly on a rendered page and edit what they see, instead of hunting through a list of content items to find the right one — works everywhere on your site, not just on the components someone remembered to tag by hand. Whether you're retrofitting an existing component library or want new components decorated correctly the first time, running it as part of your build (or as a CI drift check) means your editors get the full Web Studio experience without your team maintaining data-agility-* attributes by hand.