Skip to content

feat(action-button): S2 migration#6340

Open
cdransf wants to merge 14 commits into
mainfrom
cdransf/s2-action-button-migration
Open

feat(action-button): S2 migration#6340
cdransf wants to merge 14 commits into
mainfrom
cdransf/s2-action-button-migration

Conversation

@cdransf

@cdransf cdransf commented May 26, 2026

Copy link
Copy Markdown
Member

Description

Umbrella PR for the swc-action-button 1st-gen → 2nd-gen Spectrum 2 migration. All phase PRs target this branch and are merged here before this PR lands on main.

Migration plan: CONTRIBUTOR-DOCS/03_project-planning/03_components/action-button/migration-plan.md (merged in #6327)

Phase PRs

Phase PR Status
Phase 2 — Structure #6339 Done
Phase 3 — API #6339 Done
Phase 4 — Accessibility #6348 Done
Phase 5 — Styling #6359, #6364 Done
Phase 6 — Testing #6365 Done
Phase 7 — Documentation #6404 Done

Reviewers: individual phase PRs are the right place for line-level review. This PR is for final integration sign-off.

Motivation and context

swc-action-button is part of the Spectrum 2 component migration workstream. Key changes from 1st-gen:

  • Renders an internal native <button> as the semantic control (host no longer carries role="button")
  • Removes toggles, selected, emphasized — toggle UX moves to swc-toggle-button / swc-toggle-button-group
  • Defers hold-affordance / longpress
  • Removes the link API (href and related attributes)
  • accessible-label replaces label; aria-haspopup / aria-expanded are forwarded to the inner <button> for menu-trigger patterns
  • Adds pending state (new in 2nd-gen, matching swc-button)
  • Exposes a small reviewed set of --swc-action-button-* custom properties instead of the 1st-gen --mod-* / --spectrum-actionbutton-* chain

Related issue(s)

  • fixes SWC-2039

Author's checklist

  • I have read the CONTRIBUTING and PULL_REQUESTS documents.
  • I have reviewed the Accessibility Practices for this feature, see: Aria Practices
  • I have added automated tests to cover my changes.
  • I have included a well-written changeset if my change needs to be published.
  • I have included updated documentation if my change required it.

Reviewer's checklist

  • Includes a Github Issue with appropriate flag or Jira ticket number without a link
  • Includes thoughtfully written changeset if changes suggested include patch, minor, or major features
  • Automated tests cover all use cases and follow best practices for writing
  • Validated on all supported browsers
  • All VRTs are approved before the author can update Golden Hash

Manual review test cases

  • Default render and slot content

    1. Go to the Action Button Storybook
    2. Verify label-only, icon-only (with accessible-label), and icon + label variants all render correctly
    3. Verify quiet variant renders without a visible border at rest
    4. Verify static-color="white" and static-color="black" render with the correct foreground color
  • All sizes render correctly

    1. Go to the Action Button > Sizes story
    2. Verify xs, s, m, l, and xl all render at the expected visual scale
    3. Confirm xs is present (it is not available on swc-button)
  • Disabled state

    1. Go to the Action Button > States story
    2. Verify the disabled button is visually dimmed
    3. Try to click it — expect no click event and no activation
  • Pending state (after 1-second delay)

    1. Go to the Action Button > Pending story
    2. Verify the spinner appears after the 1-second delay
    3. Click the pending button — expect no activation
    4. Verify button width is locked during the pending state (no layout shift)
  • Breaking changes behave as documented in the consumer migration guide

    1. Go to Action Button > Migration guide in Storybook
    2. Confirm toggles, selected, emphasized, href, hold-affordance, and label are absent from the 2nd-gen API
    3. Confirm the migration guide links to swc-toggle-button / swc-toggle-button-group for toggle usage

Device review

  • Did it pass in Desktop?
  • Did it pass in (emulated) Mobile?
  • Did it pass in (emulated) iPad?

Accessibility testing checklist

  • Keyboard (required — document steps below)

    1. Go to the Action Button Storybook
    2. Press Tab to reach a default button — expect: focus ring visible on the inner <button>, not the host
    3. Press Enter and Space — expect: button activates (click fires)
    4. Tab to an icon-only button — expect: screen reader announces the accessible-label value + ", button"
    5. Tab to a pending button — expect: button is in the tab order; focus ring visible; Enter / Space do not fire click
    6. Tab to a disabled button — expect: button is skipped entirely (not in tab order)
    7. Confirm no focus trap anywhere in the stories
  • Screen reader (required — document steps below)

    1. Open the Action Button Storybook with VoiceOver (macOS) or NVDA (Windows)
    2. Focus a default button — expect: "[label], button"
    3. Focus an icon-only button — expect: "[accessible-label], button"
    4. Focus a pending button (after 1-second delay) — expect: "[label], busy, button" or platform-equivalent unavailable state
    5. Focus a disabled button — expect: "dimmed button" or equivalent unavailable state
    6. Confirm the host swc-action-button element is NOT announced as a separate button (semantics live on the inner <button>)
    7. Focus a menu-trigger button with aria-haspopup — expect: "button, has popup" announcement

@cdransf cdransf self-assigned this May 26, 2026
@cdransf cdransf added Status:WIP PR is a work in progress or draft Component:Action button do-not-merge NO MERGE-Y! Spectrum 2 Issues related to Spectrum 2 labels May 26, 2026
@changeset-bot

changeset-bot Bot commented May 26, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b22d71b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 85 packages
Name Type
@adobe/spectrum-wc Minor
@spectrum-web-components/core Minor
@spectrum-web-components/action-button Patch
@spectrum-web-components/action-group Patch
@spectrum-web-components/action-menu Patch
@spectrum-web-components/combobox Patch
@spectrum-web-components/contextual-help Patch
@spectrum-web-components/menu Patch
@spectrum-web-components/overlay Patch
@spectrum-web-components/tabs Patch
@spectrum-web-components/vrt-compare Patch
@spectrum-web-components/bundle Patch
@spectrum-web-components/action-bar Patch
@spectrum-web-components/breadcrumbs Patch
@spectrum-web-components/picker Patch
@spectrum-web-components/custom-vars-viewer Patch
@spectrum-web-components/story-decorator Patch
@spectrum-web-components/popover Patch
@spectrum-web-components/textfield Patch
@spectrum-web-components/tooltip Patch
@spectrum-web-components/truncated Patch
@spectrum-web-components/top-nav Patch
documentation Patch
@spectrum-web-components/card Patch
@spectrum-web-components/coachmark Patch
@spectrum-web-components/color-field Patch
@spectrum-web-components/number-field Patch
@spectrum-web-components/search Patch
@spectrum-web-components/slider Patch
@spectrum-web-components/accordion Patch
@spectrum-web-components/alert-banner Patch
@spectrum-web-components/alert-dialog Patch
@spectrum-web-components/asset Patch
@spectrum-web-components/avatar Patch
@spectrum-web-components/badge Patch
@spectrum-web-components/button-group Patch
@spectrum-web-components/button Patch
@spectrum-web-components/checkbox Patch
@spectrum-web-components/clear-button Patch
@spectrum-web-components/close-button Patch
@spectrum-web-components/color-area Patch
@spectrum-web-components/color-handle Patch
@spectrum-web-components/color-loupe Patch
@spectrum-web-components/color-slider Patch
@spectrum-web-components/color-wheel Patch
@spectrum-web-components/dialog Patch
@spectrum-web-components/divider Patch
@spectrum-web-components/dropzone Patch
@spectrum-web-components/field-group Patch
@spectrum-web-components/field-label Patch
@spectrum-web-components/help-text Patch
@spectrum-web-components/icon Patch
@spectrum-web-components/icons-ui Patch
@spectrum-web-components/icons-workflow Patch
@spectrum-web-components/icons Patch
@spectrum-web-components/iconset Patch
@spectrum-web-components/illustrated-message Patch
@spectrum-web-components/infield-button Patch
@spectrum-web-components/link Patch
@spectrum-web-components/meter Patch
@spectrum-web-components/modal Patch
@spectrum-web-components/picker-button Patch
@spectrum-web-components/progress-bar Patch
@spectrum-web-components/progress-circle Patch
@spectrum-web-components/radio Patch
@spectrum-web-components/sidenav Patch
@spectrum-web-components/split-view Patch
@spectrum-web-components/status-light Patch
@spectrum-web-components/swatch Patch
@spectrum-web-components/switch Patch
@spectrum-web-components/table Patch
@spectrum-web-components/tags Patch
@spectrum-web-components/thumbnail Patch
@spectrum-web-components/toast Patch
@spectrum-web-components/tray Patch
@spectrum-web-components/underlay Patch
@spectrum-web-components/base Patch
@spectrum-web-components/grid Patch
@spectrum-web-components/opacity-checkerboard Patch
@spectrum-web-components/reactive-controllers Patch
@spectrum-web-components/shared Patch
@spectrum-web-components/styles Patch
@spectrum-web-components/theme Patch
@spectrum-web-components/eslint-plugin Patch
@spectrum-web-components/stylelint-header-plugin Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

📚 Branch Preview Links

🔍 First Generation Visual Regression Test Results

When a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:

Deployed to Azure Blob Storage: pr-6340

If the changes are expected, update the current_golden_images_cache hash in the circleci config to accept the new images. Instructions are included in that file.
If the changes are unexpected, you can investigate the cause of the differences and update the code accordingly.

@cdransf cdransf force-pushed the cdransf/s2-action-button-migration branch 6 times, most recently from b028dc5 to bfb1116 Compare June 4, 2026 20:12
@cdransf cdransf force-pushed the cdransf/s2-action-button-migration branch 12 times, most recently from 7b9a44d to d04c7f8 Compare June 11, 2026 23:14
@cdransf cdransf force-pushed the cdransf/s2-action-button-migration branch 5 times, most recently from 26245eb to e5dfef0 Compare June 15, 2026 15:58
Comment thread 1st-gen/packages/action-button/src/ActionButton.ts
Comment on lines +67 to +83
public get emphasized(): boolean {
return this._emphasized;
}
public set emphasized(value: boolean) {
const oldValue = this._emphasized;
this._emphasized = value;
this.requestUpdate('emphasized', oldValue);
if (value && window.__swc?.DEBUG) {
window.__swc.warn(
this,
`The "emphasized" attribute on <${this.localName}> is deprecated and will be removed in a future release.`,
'https://opensource.adobe.com/spectrum-web-components/components/action-button/',
{ level: 'deprecation' }
);
}
}
private _emphasized = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why arent we just added a warning to the updated() lifecycle and listening for scheduledChanges? I can find another component to pattern off of.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'm not sure what scheduledChanges is? I can refactor it though if you've got an example. ✨

Comment thread 2nd-gen/packages/swc/components/button/pending-spinner.ts

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can we add transitions in and out so its not a flash?

@cdransf cdransf Jun 17, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Should we do this as part of the change to a directive? We'd have to refactor from a display based approach to one using visibility or opacity. ✨ @5t3ph

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

React is currently not using any transition, so maybe defer. There would be a bit of orchestration to get this to happen smoothly with swapping the label (and/or icon) with the spinner.

@caseyisonit caseyisonit Jun 16, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Image

Icon only isnt removing the right margin/padding between icon and label so its getting extra space

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's a Storybook template issue - see comment there

Comment on lines +128 to +132
/**
* Static color treatment for display over colored or image backgrounds.
*/
@property({ type: String, reflect: true, attribute: 'static-color' })
public staticColor?: ActionButtonStaticColor;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I called this out in the close button but maybe we need to add a todo here if you dont mind but staticColor should be on buttonBase because all button types that ive seen include it. but the solution might also be a staticColorMixin because its not just button that use static color as well

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would suggest pause on a change here and wait for close button to merge. We could further re-evaluate/refine later if that's ok @caseyisonit?

Comment thread 2nd-gen/packages/swc/components/action-button/ActionButton.ts
const validSize = (
validSizes.includes(size) ? size : fallbackSize
classValidSizes.includes(size) ? size : fallbackSize
) as ElementSize;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you explain this change and why its needed? sorry if you answered this on another PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

cant we just call VALID_SIZES do we need to call it from the constructor since this method is in the same constructor? we also override VALID_SIZES in all components pretty much. trying to wrap my head around so apologies if this is long winded.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ah! @rise-erpelding caught this on the API/TS branch too #6346 (comment)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

can everything @internal use _ prepended to the name

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The @internal methods in the action button are all overrides (VALID_SIZES, observedAttributes and attributeChangedCallback) so we can't prefix those and the others have the _ prefix. Or are there others we're missing? ✨

// Guard against re-entrant attributeChangedCallback: removeAttribute fires a
// second callback with value=null; the guard prevents that from clearing the
// state we just set.
private _ariaForwardingInProgress = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

does this need @State too?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It shouldn't, since _ariaForwardingInProgress is set to true and back to false in the same synchronous call and doesn't persist between renders or have rendered output. ✨

@5t3ph 5t3ph left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just a couple docs things!

Comment thread 2nd-gen/packages/swc/components/action-button/stories/action-button.stories.ts Outdated
Comment thread 2nd-gen/packages/swc/components/action-button/stories/action-button.stories.ts Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It's a Storybook template issue - see comment there

Comment thread 2nd-gen/packages/swc/components/action-button/ActionButton.ts Outdated
@cdransf cdransf force-pushed the cdransf/s2-action-button-migration branch from 30c08d7 to 38eef33 Compare June 17, 2026 15:19
@cdransf cdransf requested a review from 5t3ph June 17, 2026 16:56
cdransf and others added 14 commits June 17, 2026 11:07
…ponent (#6327)

* feat(action-button): adds migration plan for the S2 action button component

* chore(action-button): address feedback

* chore(action-button): address feedback
* chore(action-button): adds structure for s2 migration

* chore: clean up base class and export types

* chore(action-button): update migration plan

* chore(action-button): address feedback
* chore(action-button): migrate api and typescript code

* chore(action-button): update migration plan

* chore(action-button): api/ts self review

* chore(action-button): address feedback

* chore(action-button): address feedback
* chore(action-button): styling implementation

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): fix bug w/lit and icon only variant

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): address feedback

* Update 2nd-gen/packages/swc/.storybook/guides/customization/global-elements.mdx

Co-authored-by: Stephanie Eckles <seckles@adobe.com>

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): style guide conformance

* chore(action-button): address feedback

* chore(action-button): test suites

* chore(action-button): add a11y keyboard tests
* chore(action-button): implement accessibility features (#6348)

* chore(action-button): implement accessibility features

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): styling implementation

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): fix bug w/lit and icon only variant

* chore(action-button): address feedback

* chore(action-button): address feedback

* Update 2nd-gen/packages/swc/.storybook/guides/customization/global-elements.mdx

Co-authored-by: Stephanie Eckles <seckles@adobe.com>

* chore(action-button): style guide conformance (#6364)

* chore(action-button): styling implementation

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): address feedback

* Update 2nd-gen/packages/swc/.storybook/guides/customization/global-elements.mdx

Co-authored-by: Stephanie Eckles <seckles@adobe.com>

* chore(action-button): address feedback

---------

Co-authored-by: Stephanie Eckles <seckles@adobe.com>
* chore(action-button): implement accessibility features (#6348)

* chore(action-button): implement accessibility features

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): styling implementation

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): fix bug w/lit and icon only variant

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): style guide conformance (#6364)

* chore(action-button): styling implementation

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): storybook docs

* chore(action-button): address feedback

* Update 2nd-gen/packages/swc/components/action-button/action-button.mdx

Co-authored-by: Casey Eickhoff <48574582+caseyisonit@users.noreply.github.com>

* chore(action-button): address feedback

* chore(action-button): address feedback

* chore(action-button): fix test failure

* chore(action-button): fix test failure

* chore(action-button): author consumer migration guide (#6408)

* chore(action-button): author consumer migration guide

* chore(action-button): update migration plan

---------

Co-authored-by: Casey Eickhoff <48574582+caseyisonit@users.noreply.github.com>
Co-authored-by: Stephanie Eckles <seckles@adobe.com>
…utton.stories.ts

Co-authored-by: Stephanie Eckles <seckles@adobe.com>
@cdransf cdransf force-pushed the cdransf/s2-action-button-migration branch from fc48da9 to b22d71b Compare June 17, 2026 18:07
@5t3ph

5t3ph commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Reminder to add the run_vrt label and approve the baselines before merge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Component:Action button Spectrum 2 Issues related to Spectrum 2 Status:Ready for review PR ready for review or re-review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants