grill-me
Interview the user relentlessly about a plan or design until reaching shared understanding,…
Extending the Website Builder page settings with custom settings groups and modifiers. Use this skill when the developer wants to add a new tab/group to the page settings drawer (e.g., Publishing, Analytics, Access Control), or modify an existing settings group (e.g., add fields
$ npx -y skills add webiny/webiny-js --skill page-settings --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/page-settingsContext preview
The summary Claude sees to decide when to auto-load this skill.
Extending the Website Builder page settings with custom settings groups and modifiers. Use this skill when the developer wants to add a new tab/group to the page settings drawer (e.g., Publishing, Analytics, Access Control), or modify an existing settings group (e.g., add fields
name: webiny-page-settings-extensions description: > Extending the Website Builder page settings with custom settings groups and modifiers. Use this skill when the developer wants to add a new tab/group to the page settings drawer (e.g., Publishing, Analytics, Access Control), or modify an existing settings group (e.g., add fields to General or SEO). Covers PageSettingsGroup, PageSettingsGroupModifier, and the doc.extensions data model. For field types, renderers, and layout details, see the webiny-form-model skill.
Page settings extensions let you add new tabs to the page settings drawer or inject fields into existing tabs. Create a class implementing `PageSettingsGroup.Interface` for a new tab, or `PageSettingsGroupModifier.Interface` to extend an existing one. Register both via `createFeature()` and `<RegisterFeature>`. **Always store custom data in `doc.extensions` — never write to `doc.properties`, which is reserved for built-in system properties.**
**YOU MUST include the full file path with the `.tsx` extension in every `src` prop.** For example, use `src={"/extensions/myPageSettings/index.tsx"}`, NOT `src={"/extensions/myPageSettings/index"}`. Omitting the file extension will cause a build failure.
For field types, renderers, layout, validation, and all other form builder APIs, refer to the **webiny-form-model** skill.
> **Use `doc.extensions` for all custom data.** The `doc.properties` object holds built-in system properties (title, path, snippet, image, tags, seo, social). Writing custom fields into `doc.properties` risks naming collisions with future Webiny updates and can corrupt system behavior. Always namespace your data under `doc.extensions.<yourGroupName>`.
// CORRECT — custom data in doc.extensions
mapFromForm(formData, doc) {
doc.extensions.mySettings = doc.extensions.mySettings ?? {};
doc.extensions.mySettings.myField = formData.myField;
}
// WRONG — never write custom data into doc.properties
mapFromForm(formData, doc) {
doc.properties.myField = formData.myField; // DON'T DO THIS
}A new settings group appears as its own tab in the page settings drawer. Implement `PageSettingsGroup.Interface` with these members:
| Member | Type | Description | | ---------------------------- | ------------------------------------------- | --------------------------------------------------------- | | `name` | `string` | Unique group identifier (used as form field namespace) | | `label` | `string` | Tab label shown in the UI | | `description` | `string` (optional) | Description shown below the tab label | | `icon` | `{ type: "icon", name: string }` (optional) | FontAwesome icon for the tab (e.g., `"fas/calendar-alt"`) | | `buildForm(form)` | method | Define fields and layout | | `mapToForm(doc)` | method | Read from document to populate the form | | `mapFromForm(formData, doc)` | method | Write form values back to the document |
// extensions/myPageSettings/PublishingSettingsGroup.ts
import { PageSettingsGroup } from "webiny/admin/website-builder/page/editor";
class PublishingSettingsGroupImpl implements PageSettingsGroup.Interface {
name = "publishing";
label = "Publishing";
description = "Configure publishing schedule and visibility.";
icon = { type: "icon", name: "fas/calendar-alt" };
buildForm(form: PageSettingsGroup.FormBuilder): void {
form.fields(fields => ({
publishDate: fields.datetime().withTimezone().label("Publish date"),
unpublishDate: fields.datetime().dateOnly().label("Unpublish date"),
visibility: fields
.text()
.label("Visibility")
.options([
{ label: "Public", value: "public" },
{ label: "Private", value: "private" },
{ label: "Password Protected", value: "password" }
])
.defaultValue("public"),
featured: fields.boolean().label("Featured page")
}));
form.layout(layout => [
layout.row("publishDate"),
layout.row("unpublishDate"),
layout.row("visibility"),
layout.row("featured")
]);
}
mapToForm(doc: PageSettingsGroup.PageDocument): Record<string, any> {
const publishing = doc.extensions?.publishing;
return {
publishDate: publishing?.publishDate ?? null,
unpublishDate: publishing?.unpublishDate ?? null,
visibility: publishing?.visibility ?? "public",
featured: publishing?.featured ?? false
};
}
mapFromForm(formData: Record<string, any>, doc: PageSettingsGroup.PageDocument): void {
doc.extensions.publishing = doc.extensions.publishing ?? {};
doc.extensions.publishing.publishDate = formData.publishDate;
doc.extensions.publishing.unpublishDate = formData.unpublishDate;
doc.extensions.publishing.visibility = formData.visibility;
doc.extensions.publishing.featured = formData.featured;
}
}
export const PublishingSettingsGroup = PageSettingsGroup.createImplementation({
implementation: PublishingSettingsGroupImpl,
dependencies: []
});A modifier injects fields into an existing tab without subclassing it. Implement `PageSettingsGroupModifier.Interface`:
| Member | Type | Description
Open-source content platform. Self-hosted on AWS serverless. Built as a TypeScript framework you extend with code, not a closed product you configure through a UI. Runs on Lambda, DynamoDB, S3, and CloudFront inside your own AWS account. Scales automatically.
Repo: webiny/webiny-js
Interview the user relentlessly about a plan or design until reaching shared understanding,…
Turn a PRD into a multi-phase implementation plan using tracer-bullet vertical slices, saved…
Webiny-only. Run all checks required before packages are ready for publish: deps, build,…
Use when running tests. Shows how to run tests for a single package, including OpenSearch…
Generate, refresh, and maintain Webiny MCP server skills from source documentation and…
Create a PRD through user interview, codebase exploration, and module design, then submit as…