Skip to content

Document and type the form widget contract - #97

Merged
sneridagh merged 10 commits into
mainfrom
widgetsDefinitions
Oct 10, 2026
Merged

sneridagh merged 10 commits into
mainfrom
widgetsDefinitions

Conversation

@sneridagh

@sneridagh sneridagh commented Jun 4, 2026 •

Copy link
Copy Markdown
Member

Step 1 of #243 (define and enforce the form widget contract).

  • Adds the conceptual guide "Form fields, controls, and widgets", which explains the field / control / widget / adapter split and the rule that only widgets are registered.
  • Adds the shared FormWidgetProps<T> / FormWidget<T> types to @plone/types. value comes in as T | null (it can be empty) and onChange emits a normalized T.
  • BooleanWidget now uses the shared type.
  • Field.tsx wires onBlur to TanStack Form (touched state and blur validation), converts error to errors / errorMessage, and stops overwriting a label passed by the caller.

The BooleanWidget adapter itself landed on main with #220. This PR now carries the contract types and docs. The remaining inconsistencies are tracked in #243, which has the plan for follow-up PRs.

Originally transferred from plone/volto#8309, and supersedes plone/volto#8237 and plone/volto#8247.

sneridagh and others added 5 commits June 2, 2026 15:28
* seven:
  Update README with the Plone Aurora
  Seven querystringWidget (#8017)
  [Seven] Add `renderEmptyState` to `Table` component (#8308)
  Recurrence widget (#7200)
Co-authored-by: Steve Piercy <web@stevepiercy.com>
@stevepiercy

Copy link
Copy Markdown
Member

@sneridagh https://www.dlr.de/de keeps timing out in the README linkcheck.

@stevepiercy stevepiercy left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't have a firm grasp of the differences between field, control, and widget. Adapter kind of makes sense to me as the glue between a control and a widget. Is there a diagram or external documentation that we can reuse? I need a picture or more code examples.

In my tiny dinosaur brain:

We should also add all these terms into a glossary.

## Design implications

The form generator should be basic.
It should resolve widgets, pass normalized field props, and connect changes back to form state.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It should resolve widgets, pass normalized field props, and connect changes back to form state.
It should resolve widgets, pass normalized field props, and connect changes back to the form state.

Comment on lines +183 to +185
It should not contain special cases for checkbox selection state, date serialization, upload workflows, relation values, or vocabulary fetching.

Widgets should own those differences.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this sentence belongs better with the previous paragraph, forming a complete concept of what it means to keep the form generator basic.

Then the next paragraph explains why that's advantageous, and where the complicated pieces belong.

Suggested change
It should not contain special cases for checkbox selection state, date serialization, upload workflows, relation values, or vocabulary fetching.
Widgets should own those differences.
It should not contain special cases for checkbox selection state, date serialization, upload workflows, relation values, or vocabulary fetching.
Widgets should own those differences.


(form-fields-controls-and-widgets-label)=

# Form fields, controls, and widgets

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Form fields, controls, and widgets
# Form fields, controls, widgets, and adapters

html_meta:
"description": "An explanation of fields, controls, widgets, and widget adapters in Seven forms"
"property=og:description": "An explanation of fields, controls, widgets, and widget adapters in Seven forms"
"property=og:title": "Form fields, controls, and widgets"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"property=og:title": "Form fields, controls, and widgets"
"property=og:title": "Form fields, controls, widgets, and adapters"

"description": "An explanation of fields, controls, widgets, and widget adapters in Seven forms"
"property=og:description": "An explanation of fields, controls, widgets, and widget adapters in Seven forms"
"property=og:title": "Form fields, controls, and widgets"
"keywords": "Seven, forms, fields, controls, widgets, @tanstack/form, @plone/cmsui"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"keywords": "Seven, forms, fields, controls, widgets, @tanstack/form, @plone/cmsui"
"keywords": "Aurora, forms, fields, controls, widgets, adapters, @tanstack/form, @plone/cmsui"

Comment on lines +4 to +5
"description": "An explanation of fields, controls, widgets, and widget adapters in Seven forms"
"property=og:description": "An explanation of fields, controls, widgets, and widget adapters in Seven forms"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"description": "An explanation of fields, controls, widgets, and widget adapters in Seven forms"
"property=og:description": "An explanation of fields, controls, widgets, and widget adapters in Seven forms"
"description": "An explanation of fields, controls, widgets, and widget adapters in Aurora forms"
"property=og:description": "An explanation of fields, controls, widgets, and widget adapters in Aurora forms"


# Form fields, controls, and widgets

Seven forms are schema-driven.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Seven forms are schema-driven.
Aurora forms are schema-driven.

The form state system asks, "What is the value and validation state of this field?"
The widget registry asks, "Which widget should render this field?"

Seven can resolve a widget from several schema hints.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Seven can resolve a widget from several schema hints.
Aurora can resolve a widget from several schema hints.


## Control

A control is a lower-level interactive component.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lower-level than what? Field? Widget?

import { BooleanWidget } from './BooleanWidget';

const meta = {
title: 'CMS UI/Widgets/BooleanWidget',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
title: 'CMS UI/Widgets/BooleanWidget',
title: 'CMSUI/Widgets/BooleanWidget',

@sneridagh sneridagh mentioned this pull request Oct 4, 2026
9 tasks done
sneridagh added a commit that referenced this pull request Oct 7, 2026
Wire the control panel action to PATCH @ControlPanels, port the BooleanWidget adapter from #97 so boolean fields show their label and value, and replace the react-aria toolbar buttons in the control panel routes, whose onPress never fires inside the toolbar's shadow root.
* origin/main: (190 commits)
  Make control panels saveable (#220)
  Public UI: render a single .content-area root (#230) (#234)
  Remove tsconfig test/spec/story excludes that never matched any file (#222)
  Add PloneClient.extend() and clientEndpoints utility for custom endpoints (#221)
  Store the default block width of every top-level block (#190)
  Releasing @plone/aurora 1.0.0-alpha.19
  Release @plone/cmsui 1.0.0-alpha.12
  Release @plone/agave 1.0.0-alpha.9
  Release @plone/theming 1.0.0-alpha.9
  Release @plone/layout 1.0.0-alpha.14
  Release @plone/blocks 1.0.0-alpha.18
  Release @plone/plate 1.0.0-alpha.25
  Release @plone/registry 4.0.0-alpha.5
  Release @plone/quanta 1.0.0-alpha.2
  Content CSS Phase 11: theming guide for blocks and cleanup (#219)
  Rename the Plone blocks' classnames to the content contract (#218)
  Share the block spacing between the Public UI and the editor (#217)
  Content CSS Phase 8: structural blocks and content root to styles/content.css (#216)
  Remove the Plate media nodes from Aurora's presets (#215)
  Move the table styles to styles/content.css (#214)
  ...

# Conflicts:
#	packages/cmsui/components/BooleanWidget/BooleanWidget.stories.tsx
#	packages/cmsui/components/BooleanWidget/BooleanWidget.test.tsx
#	packages/cmsui/components/BooleanWidget/BooleanWidget.tsx
#	packages/cmsui/news/+boolean-widget-adapter.bugfix
@sneridagh sneridagh changed the title BooleanWidget and clarify widgets definitions in documentation Document and type the form widget contract Oct 8, 2026
Address the review: add a diagram that follows one field from its schema
to its control and back, a comparison with HTML form controls and
database columns, worked adapter examples for a boolean and a date
widget, and a glossary. Apply the suggested wording and title changes.

Add the missing cmsui and docs news fragments.
@sneridagh

Copy link
Copy Markdown
Member Author

@stevepiercy thanks for the review. I reworked the guide in 4ed03e8:

  • A picture: a new diagram follows one field, exclude_from_nav, from its schema to the checkbox and back (isSelected = true becomes onChange(true)).
  • Your mental model: a new table compares each concept to what you described. It's mostly right:
    • A control is the HTML form control. In Aurora it's usually a Quanta / React Aria component that renders one.
    • A field is like a column in a relational table, plus the value being edited and its form state.
    • The one difference is widgets: in Plone, every field gets a widget, even a simple text input. Complex pickers are widgets too, but size isn't what makes something a widget; the shared props are.
  • More code examples: the boolean adapter now comes with a prop mapping table, and there's a second example, a date adapter that converts values (ISO string ↔ DateValue).
  • "Lower-level than what?": now explicit. A control is the lowest layer, the interactive element itself.
  • Glossary: the guide ends with a glossary section (field, control, widget, adapter, widget contract, widget registry). Our {term} references resolve to the Plone 6 docs glossary, so if you agree with the definitions, I can open a PR in plone/documentation to add them there.
  • I applied all your inline suggestions (title, metadata, wording, paragraph order). I used "Plone Aurora" rather than "Aurora", to match the rest of these docs.

The rest of the contract work is tracked in #243.

* origin/main:
  Scope widget lookups to their category (#249)
  Subscribe only to the form fields that are read (#248)
  Give each form its own store and remount it per item (#247)
  Wait for hydration in sharing acceptance tests (#250)
* origin/main:
  Fix the recurrence modal crash for events ending on days 1 to 9 (#255)
@sneridagh
sneridagh added this pull request to stack #258 October 9, 2026 16:21
@sneridagh
sneridagh requested a review from pnicolli October 9, 2026 19:41
@sneridagh
sneridagh merged commit 0084abf into main Oct 10, 2026
42 checks passed
@sneridagh
sneridagh deleted the widgetsDefinitions branch October 10, 2026 22:38
sneridagh added a commit that referenced this pull request Oct 10, 2026
* origin/main:
  Validate schema-driven forms (#256)
  Move the recurrence modal off TanStack Form (#254)
  Move the forms onto the helpers form store (#253)
  Add a Jotai-native form layer to helpers (#252)
  Render every schema form through one field renderer (#251)
  Document and type the form widget contract (#97)
  Match utility dependencies exactly in the registry (#259)

# Conflicts:
#	packages/cmsui/config/widgets.ts
sneridagh added a commit that referenced this pull request Oct 10, 2026
…widget-context

* origin/feat/widget-adapters:
  Restore files the pre-commit hook reformatted
  Validate schema-driven forms (#256)
  Move the recurrence modal off TanStack Form (#254)
  Move the forms onto the helpers form store (#253)
  Add a Jotai-native form layer to helpers (#252)
  Render every schema form through one field renderer (#251)
  Document and type the form widget contract (#97)
  Match utility dependencies exactly in the registry (#259)
sneridagh added a commit that referenced this pull request Oct 10, 2026
…yped-widget-registry

* origin/feat/widget-context:
  Restore files the pre-commit hook reformatted
  Validate schema-driven forms (#256)
  Move the recurrence modal off TanStack Form (#254)
  Move the forms onto the helpers form store (#253)
  Add a Jotai-native form layer to helpers (#252)
  Render every schema form through one field renderer (#251)
  Document and type the form widget contract (#97)
  Match utility dependencies exactly in the registry (#259)
sneridagh added a commit that referenced this pull request Oct 10, 2026
… feat/missing-widgets

* origin/feat/typed-widget-registry:
  Restore files the pre-commit hook reformatted
  Validate schema-driven forms (#256)
  Move the recurrence modal off TanStack Form (#254)
  Move the forms onto the helpers form store (#253)
  Add a Jotai-native form layer to helpers (#252)
  Render every schema form through one field renderer (#251)
  Document and type the form widget contract (#97)
  Match utility dependencies exactly in the registry (#259)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants