Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
- [What to do](#what-to-do)
- [Property migration scenarios](#property-migration-scenarios)
- [API patterns (statics and warnings)](#api-patterns-statics-and-warnings)
- [Form participation (form fields only)](#form-participation-form-fields-only)
- [What to check](#what-to-check)
- [Common problems and solutions](#common-problems-and-solutions)
- [Quality gate](#quality-gate)
Expand Down Expand Up @@ -356,13 +357,21 @@ Notes on the pattern:
- The URL links to the component docs section that describes the new API.
- `level: 'deprecation'` sorts the warning under the deprecation channel and lets consumers silence the whole class via `window.__swc.ignoreWarningLevels.deprecation = true`.

### Form participation (form fields only)

Applies when the component is a **form field** (text field, checkbox, radio, picker, combobox). Skip this for non-form components.

Wire the field per the approved [forms strategy](../../../05_strategies/forms-strategy-rfc.md): form participation through the **ElementInternals / form-associated custom element (FACE)** API (not a nested light-DOM `<input>`) and the form lifecycle callbacks. Name the public API from its [naming table](../../../05_strategies/forms-strategy-rfc.md#4-naming-table) so property, slot, and event names match; do not invent per-component names, and align text-like fields and pickers to the same table.

### What to check

- [ ] All relevant 1st-gen props have a 2nd-gen home (base or SWC).
- [ ] Types are in core and used by SWC.
- [ ] Internal helpers are marked `@internal`.
- [ ] Static `readonly` arrays match types; used for validation, Storybook, and tests where applicable.
- [ ] Invalid prop combinations emit `window.__swc.warn()` when debug is on (where the component has combination rules).
- [ ] **Form fields:** the field is form-associated (`static formAssociated = true`); value flows through `ElementInternals` (`setFormValue()`), not a hidden `<input>`; and property, slot, and event names match the forms strategy naming table. (Validity reporting via `setValidity()` is pending — do not block on it.)


### Common problems and solutions

Expand Down Expand Up @@ -399,6 +408,7 @@ If you are renaming or removing a public prop or attribute, confirm with the tea
6. **Native vs custom controls:** Native form control (e.g. Checkbox) → `delegatesFocus: true`. Custom control (e.g. Radio) → `role` and `aria-*` on host, manage focus/keyboard. See Checkbox and Radio as references.
7. **Focus delegation on internal control:** When a component wraps a native form control inside its shadow DOM, set `delegatesFocus: true` via `static override shadowRootOptions = { ...ParentClass.shadowRootOptions, delegatesFocus: true }` so that focus lands on the internal control, not the host. This belongs in the base class if all subclasses share the same host-wraps-native-control structure. **Do not** override `createRenderRoot()` to set this option — doing so bypasses Lit’s `adoptStyles()`, silently preventing all component CSS from being injected into the shadow DOM. See [Rendering patterns: Shadow root customization](../../../../02_style-guide/02_typescript/09_rendering-patterns.md#shadow-root-customization).
8. **Accessible name forwarding:** Attributes like `aria-label` on the host do not automatically apply to the internal control — either bind them explicitly in the render template (e.g. `aria-label=${this.getAttribute(‘aria-label’)}`) or derive the accessible name in a protected helper and forward it. See `ButtonBase.getResolvedAccessibleName()` as a reference. Note that implementing these patterns may require adding methods or modifying the render template, so Phase 4 often touches component class files, not only Storybook or docs.
9. **Form field label, help text, and errors (form fields only):** Wire the accessible name, help text, and error text per the approved [forms strategy](../../../05_strategies/forms-strategy-rfc.md#33-idref-strategy-label-help-text-and-errors), which covers the labelling surface, `aria-describedby` / `aria-errormessage`, and the cross-root IDREF pattern. See also [semantic HTML and ARIA](../../../../../2nd-gen/packages/swc/.storybook/guides/accessibility-guides/semantic_html_aria.mdx).

### What to check

Expand All @@ -416,6 +426,7 @@ If you are renaming or removing a public prop or attribute, confirm with the tea
| Unclear which pattern applies | Start from the component’s primary role (e.g. "combobox" → Combobox pattern). Consider splitting into more than one component (e.g. "sp-menu" into menu and listbox components). |
| Focus trap in overlays | Use a shared focus-trap utility if the repo provides one; follow APG for modal/dialog. |
| Custom controls | Ensure they have roles, names, and keyboard support; avoid div/span without semantics. |
| Help text or error not announced | The describing text lives in a different shadow root; a bare `aria-describedby` IDREF does not cross the boundary. Use the cross-root pattern from the [forms strategy](../../../05_strategies/forms-strategy-rfc.md#33-idref-strategy-label-help-text-and-errors). |

<details>
<summary>**Stop and ask:** Custom events vs native events</summary>
Expand All @@ -431,6 +442,7 @@ Prefer native events when they give the right semantics (e.g. `click`). Add cust
- [ ] Keyboard and ARIA implemented
- [ ] a11y tests added
- [ ] Screen reader testing performed
- [ ] **Form fields:** axe-core passes in CI. Any known false positive (e.g. a role exposed through `ElementInternals` that axe cannot yet see) is handled per the forms strategy [axe policy](../../../05_strategies/forms-strategy-rfc.md#34-axe-core-policy): a story-level exclusion with a written rationale and an upstream tracking link, not a silent disable.

---

Expand Down Expand Up @@ -656,6 +668,7 @@ Use Badge as the reference implementation:

## Style guides and resources

- **Forms strategy:** [2nd-gen forms strategy](../../../05_strategies/forms-strategy-rfc.md) — ElementInternals/FACE decision, label/help/error pattern, IDREF and cross-root rules, and axe policy for form fields.
- **Workspace:** [spectrum-css](https://github.com/adobe/spectrum-css) cloned **next to** this repo—see [Workspace setup](#workspace-setup).
- **TypeScript:** Team conventions; for 2nd-gen API patterns (static `readonly`, `window.__swc.warn`), see Phase 3 [API patterns](#api-patterns-statics-and-warnings) and 2nd-gen Badge (`core` + `swc`).
- **CSS:** [2nd-gen CSS style guide (CONTRIBUTOR-DOCS)](../../../../02_style-guide/01_css/README.md) — component CSS, custom properties, Spectrum→SWC migration, anti-patterns, property order
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,5 @@ This section provides a **component-centric view** of individual components and
Each component has its own folder (kebab-case). Inside you'll find analysis and planning docs for that component—for example, **rendering-and-styling-migration-analysis.md** for Spectrum 2 CSS-to-SWC migration. The same structure is intended for future peer docs (e.g. a11y analysis, comparative API analysis).

For a workstream-centric view of the same work, see [Workstreams](../02_workstreams/README.md). For how the two views fit together, see the [Project planning overview](../README.md).

When migrating a **form field** (text field, checkbox, radio, picker, combobox, and similar), start from the canonical [forms strategy](../05_strategies/forms-strategy-rfc.md): it defines the ElementInternals/FACE decision, the label/help/error pattern, IDREF and cross-root rules, and the axe policy that Phase 3 and Phase 4 of the [washing machine workflow](../02_workstreams/02_2nd-gen-component-migration/02_step-by-step/01_washing-machine-workflow.md) depend on.
Loading
Loading