CONTRIBUTOR-DOCS / Project planning / Components / Close Button / Close button migration plan
Close button migration plan
In this doc
Epic SWC-2087 · Planning output. Must be reviewed before implementation begins.
swc-close-button should ship as a dedicated 2nd-gen component in both core and swc layers, not as an extension point buried inside swc-button.
API should align with modern button conventions: accessible-label (consumer-facing), static-color, and size (s|m|l|xl).
Variant aliases from 1st-gen (variant="white|black") should be deprecated in favor of static-color.
Styling source of truth is Spectrum CSS spectrum-two components/closebutton; 2nd-gen should not re-expose the 1st-gen --mod-closebutton-* surface.
Accessibility is must-ship: real inner <button type="button">, delegated focus, mandatory discernible name, and keyboard parity for Enter/Space.
Most blocking open questions
Q1 : Confirm whether icon-size should be a public API in SWC or kept internal.
Source: 1st-gen/packages/button/src/CloseButton.ts
Version: @spectrum-web-components/button@1.x
Custom element tag: sp-close-button
Property
Type
Default
Attribute
Notes
size
's' | 'm' | 'l' | 'xl'
no reflected default (noDefaultSize)
size
Visual default behaves as medium when omitted.
variant
'white' | 'black' | ''
''
variant
Legacy static-color alias.
staticColor
'white' | 'black' | undefined
undefined
static-color
Preferred static color signal in 1st-gen.
label
string | undefined
undefined
label
Accessible name channel inherited from button base stack.
disabled
boolean
false
disabled
Inherited interaction state.
No close-button-specific public methods.
No close-button-specific custom events.
Slot
Content
Notes
default
Accessible text label
Rendered in a visually hidden span next to the cross icon.
icon
Not consumer-authored
Internal cross icon is rendered by component code.
1st-gen styling depends on --mod-closebutton-* and related inherited --mod-button-* pass-throughs. This surface is not carried forward to 2nd-gen.
Shadow DOM output (rendered HTML)
< sp-icon-cross300 slot ="icon " class ="icon spectrum-UIIcon-Cross300 "> </ sp-icon-cross300 >
< span id ="label " class ="visually-hidden ">
< slot > </ slot >
</ span >
Package
Version
Role
@spectrum-web-components/base
1st-gen
Sized mixin and template base
@spectrum-web-components/button
1st-gen
StyledButton/ButtonBase inheritance
@spectrum-web-components/close-button
1st-gen
Close button CSS bundle
@spectrum-web-components/icons-ui
1st-gen
Cross icon set (200-500)
Migration sequencing and prerequisites
close-button should follow this order:
Finish this plan and rendering analysis.
Scaffold 2nd-gen core and swc close-button files.
Land API + accessibility behavior before visual parity.
Land S2 styling and then tests/docs.
Prerequisite dependency:
ButtonBase behavior in 2nd-gen button stack should be treated as the contract baseline for focus, naming, and disabled semantics.
Must ship — breaking or a11y-required
#
What changes
1st-gen behavior
2nd-gen behavior
Consumer migration path
B1
Tag rename
<sp-close-button>
<swc-close-button>
Rename markup and import path.
B2
Accessible name channel rename
label
accessible-label
Rename attribute/property and keep semantics identical.
B3
Static color API cleanup and deprecation
`variant="white
black"andstatic-color` both allowed
static-color is canonical; variant is deprecated in this migration and scheduled for removal after deprecation window
#
What changes
1st-gen behavior
2nd-gen behavior
Consumer migration path
B4
Remove legacy modifier surface
--mod-closebutton-* overrides
Reviewed --swc-close-button-* only
Migrate to published 2nd-gen custom props.
B5
S2 token parity
Legacy token references and class stack
S2 token mapping from spectrum-two closebutton CSS
Visual diff review against S2 resources.
Accessibility and behavior
#
What changes
1st-gen behavior
2nd-gen behavior
Consumer migration path
B6
Semantic button implementation
Host-level semantics from legacy stack
Real inner <button type="button"> + delegated focus
No API change; update tests asserting internals.
B7
Required discernible name
Can rely on hidden slot or label
Must always expose accessible name (accessible-label or slot text)
Ensure every usage has clear name text.
Additive — ships when ready, zero breakage for consumers already on 2nd-gen
#
What is added
Notes
A1
Optional icon-scale API (icon-size)
Add only if design and implementation both require it.
A2
Expanded public custom property set
Keep minimal initially; expand only for proven consumer needs.
Property
Type
Default
Attribute
Confidence
size
's' | 'm' | 'l' | 'xl'
'm'
size
Confirmed
staticColor
'white' | 'black' | undefined
undefined
static-color
Confirmed
accessibleLabel
string | undefined
undefined
accessible-label
Confirmed
disabled
boolean
false
disabled
Confirmed
variant (deprecated alias)
'white' | 'black' | ''
''
variant
Deprecated in 2nd-gen close-button migration; map to static-color with deprecation warning during transition, then remove.
Component must be a dismiss control, not a clear/reset control.
Enter and Space activate like native button behavior.
Focus-visible ring behavior must match S2 closebutton semantics including forced-colors compatibility.
Accessibility semantics notes (2nd-gen)
Apply recommendations in accessibility-migration-analysis.md for role/name/keyboard/focus.
Do not duplicate host role="button" if inner button is the real focus target.
Architecture: core vs SWC split
core: CloseButton.base.ts, types, validations, semantic contracts.
swc: render template, CSS, element registration, stories, tests.
Reuse button-base patterns where possible, but keep close-button semantics distinct from clear-button.
Preparation (this ticket)
Blockers and open questions
Architecture and behavior
#
Item
Blocking?
Status
Owner
Q1
Should icon-size be exposed in public API, or remain internal visual implementation detail?
Yes
Open
Design + implementation
#
Item
Blocking?
Status
Owner
Q2
No additional scope or prerequisite blockers identified at this time.
No
Resolved
Ticket owner