Skip to content

feat(infield-button): migrate CSS and stories for Phase 5 (styling) - #6499

Merged
Rajdeepc merged 7 commits into
swc-2105/infield-buttonfrom
rajdeepc/feat-infield-button-migration-phase-5
Jul 30, 2026
Merged

feat(infield-button): migrate CSS and stories for Phase 5 (styling)#6499
Rajdeepc merged 7 commits into
swc-2105/infield-buttonfrom
rajdeepc/feat-infield-button-migration-phase-5

Conversation

@Rajdeepc

@Rajdeepc Rajdeepc commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Description

Phase 5 (styling) of the 1st-gen → 2nd-gen swc-infield-button migration, updated to address review feedback.

CSS (infield-button.css)

  • Padding-based sizing: the host has no fixed block/inline size. The inner button self-sizes via padding: var(--swc-infield-button-padding, token("accessory-item-padding-medium")) plus icon. Consuming fields control outer dimensions and spacing.
  • Per-size overrides on :host([size="*"]) set public custom properties that cascade into the button:
    • S: --swc-infield-button-paddingaccessory-item-padding-small (3px)
    • M (default): 5px padding via fallback; no host rule needed
    • L: --swc-infield-button-paddingaccessory-item-padding-large (7px); --swc-infield-button-icon-sizeworkflow-icon-2x-small (12px)
    • XL: --swc-infield-button-paddingaccessory-item-padding-extra-large (9px); --swc-infield-button-icon-sizeworkflow-icon-extra-small (14px)
  • Icon sizes (corrected per Spectrum CSS reference): S/M → workflow-icon-3x-small (10px, default), L → workflow-icon-2x-small (12px), XL → workflow-icon-extra-small (14px). Icon size is resolved inside the ::slotted() rule, following the button.css pattern.
  • Quiet state: only the base quiet treatment (transparent background and border) is explicit; hover/active/focus-visible states for quiet are handled by the semantic button element and require no overrides.
  • Active transform: kept — provides tactile click feedback for interactive uses (e.g., number field stepper). Exposed via --swc-infield-button-down-state-transform.
  • Border radius: four individual border-*-radius custom properties so parent fields can zero out inner corners without losing the outer radius.
  • Forced colors: system-color tokens at the bottom of the file.

Stories (stories/infield-button.stories.ts)

All stories show swc-infield-button inside a labeled mock field using plain HTML, since 2nd-gen field components are not yet migrated. This enables meaningful axe accessibility testing and models correct consumer usage. Contexts shown:

  • Picker/combobox (chevron button at the trailing edge of a text input)
  • Search field with a clear button (cross button at the trailing edge)
  • Number field stepper (decrement + increment buttons flanking a number input)

InfieldButton.ts

@cssprop documentation updated: --swc-infield-button-height removed (no longer exists); --swc-infield-button-padding added.

Motivation and context

Phase 5 of the infield-button migration workstream translates the 1st-gen sp-infield-button visual layer to 2nd-gen S2 design tokens and SWC CSS conventions, and adds the Storybook stories surface needed for Phase 6 testing.

Related issue(s)

  • Part of epic SWC-2105

Screenshots (if appropriate)

N/A — CSS and stories changes; visual verification done in Storybook.

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

  • Verify the button sizes correctly at each size attribute value

    1. Open the Sizes story in Storybook
    2. Compare the button at S, M, L, XL inside the mock field
    3. Expect the button to be visually proportional to the field height at each size, with no extra forced padding outside the button
  • Verify press-state (downstate) transform animates correctly

    1. Open the States story in Storybook
    2. Click and hold the enabled button inside the mock field
    3. Expect the button to shift slightly into the screen (tactile press effect) and release on pointer-up
  • Verify quiet variant has no visible border or background

    1. Open the Quiet story in Storybook
    2. Hover and click the quiet button inside the borderless mock field
    3. Expect background and border remain transparent; hover state uses default interaction colors
  • Verify forced-colors (high-contrast) rendering

    1. Enable Windows High Contrast or forced-colors emulation in DevTools
    2. Open any infield-button story
    3. Expect icon color, background, and border use system color tokens correctly

Device review

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

Accessibility testing checklist

  • Keyboard (required)

    1. Open the Accessibility story (number field stepper) in Storybook
    2. Tab into the story — the input receives focus; Tab again moves past the field
    3. Expect swc-infield-button is never focused (tabindex="-1"); the parent field owns keyboard behavior
  • Screen reader (required)

    1. Open the Accessibility story with VoiceOver (macOS) or NVDA (Windows)
    2. Navigate to the quantity field
    3. Expect: the label "Quantity" is announced on the input; each swc-infield-button announces its role ("button") and its aria-label ("Decrease quantity" / "Increase quantity") when navigated via the accessibility tree

@Rajdeepc
Rajdeepc requested a review from a team as a code owner July 13, 2026 07:36
@changeset-bot

changeset-bot Bot commented Jul 13, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 1c6e5c5

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@Rajdeepc Rajdeepc self-assigned this Jul 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📚 Branch Preview Links

🔍 Gen1 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-6499

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.

@Rajdeepc Rajdeepc added Status:Ready for review PR ready for review or re-review. gen2 These issues or PRs map to our 2nd generation work to modernizing infrastructure. labels Jul 13, 2026

@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.

Refactor needed - let me know if you want assistance converting this!

Comment thread 2nd-gen/packages/swc/components/infield-button/infield-button.css
@Rajdeepc
Rajdeepc requested a review from 5t3ph July 14, 2026 08:56

@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.

More refactor steps are needed to bring this up to S2 expectations, following the example of S2 Number Field.

Comment thread 2nd-gen/packages/swc/components/infield-button/infield-button.css Outdated
Comment thread 2nd-gen/packages/swc/components/infield-button/infield-button.css
Comment thread 2nd-gen/packages/swc/components/infield-button/infield-button.css Outdated
Comment thread 2nd-gen/packages/swc/components/infield-button/infield-button.css Outdated
Comment thread 2nd-gen/packages/swc/components/infield-button/infield-button.css

@nikkimk nikkimk 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.

Since an infield button is only ever used in a field and not as a standalone component, the examples should show it used inside fields accessibly. This allows us to fully test for accessibility as well as model to our consumers how to use this component.

Comment thread 2nd-gen/packages/swc/components/infield-button/infield-button.css
Comment thread 2nd-gen/packages/swc/components/infield-button/infield-button.css Outdated
@Rajdeepc

Rajdeepc commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

Since an infield button is only ever used in a field and not as a standalone component, the examples should show it used inside fields accessibly. This allows us to fully test for accessibility as well as model to our consumers how to use this component.

Agreed but this depends on swc-picker and swc-numberfield being visually ready. If I add a contrived wrapper that would misrepresent actual usage. I'd like to track this as a follow-up once those components are available. For now, the component's own accessibility contract is narrow by design: accessible-label maps to aria-label on the inner <button>, and tabindex="-1" keeps it out of the tab order. I've verified that contract is wired correctly.

Screenshot 2026-07-16 at 4 32 32 PM

@Rajdeepc
Rajdeepc requested review from 5t3ph and nikkimk July 16, 2026 14:00

@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.

The padding and icon size related adjustments look good!

Some remaining cleanup of custom property use.

Comment thread 2nd-gen/packages/core/components/infield-button/InfieldButton.base.ts Outdated
Comment thread 2nd-gen/packages/swc/components/infield-button/infield-button.css Outdated
Comment thread 2nd-gen/packages/swc/components/infield-button/infield-button.css
Comment thread 2nd-gen/packages/swc/components/infield-button/infield-button.css Outdated
Comment thread 2nd-gen/packages/swc/components/infield-button/infield-button.css Outdated
Comment thread 2nd-gen/packages/swc/components/infield-button/infield-button.css Outdated
@Rajdeepc
Rajdeepc force-pushed the rajdeepc/feat-infield-button-migration-phase-5 branch from 27a9133 to b4b9692 Compare July 17, 2026 08:02
@Rajdeepc
Rajdeepc requested a review from 5t3ph July 17, 2026 14:11
@Rajdeepc
Rajdeepc force-pushed the swc-2105/infield-button branch from 7961190 to a77804c Compare July 21, 2026 07:06
Rajdeep Chandra and others added 5 commits July 21, 2026 12:37
… treatment

Migrates infield-button CSS to 2nd-gen structure with Spectrum 2 tokens.
Removes decorative border (gray-100 background provides visual separation);
keeps forced-colors border for accessibility. Quiet variant sets
background-color:transparent only. Press transform uses perspective() with
a valid <length> derived from padding and icon-size. Stories and MDX authored.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use private --_swc-infield-button-padding and --_swc-infield-button-icon-size
  to eliminate duplication in the block-size calc and padding declarations
- Remove the five exposed border-radius custom properties; corner radius is
  now a direct token() call managed by the consuming field
- Move quiet treatment to host-level custom property overrides matching
  the action-button pattern; add --swc-infield-button-background-color-disabled
  so disabled+quiet composes correctly
- Change slotted icon selector to ::slotted([slot="icon"])
- Reduce forced-colors block to base and disabled rules only; remove the
  hover/active/focus-visible block and add an explicit border for visibility
- Update @cssprop tags to match

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…om InfieldButtonBase

ButtonBase does not declare pending or pendingLabel, so the @State() override
modifiers were causing TS4113 errors. Infield buttons intentionally have no pending
state — the parent field host owns busy UI and disables slotted buttons while pending.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The browser's native <button> element already maps colors correctly
in forced-colors mode without an explicit override. Re-mapping
ButtonText/ButtonFace/ButtonBorder is what the browser does
automatically, and forced-color-adjust: none opts out of that
behavior unnecessarily. Other components (action-button, button)
only add forced-colors rules for things the browser cannot infer
automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The base style sets border: none, which removes the button's visual
boundary in forced-colors mode. Add back just `border: 1px solid` so
the UA maps it to ButtonBorder automatically — no color override needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Rajdeepc
Rajdeepc force-pushed the rajdeepc/feat-infield-button-migration-phase-5 branch from 9f5d5c8 to 0856170 Compare July 21, 2026 07:07

@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.

Thanks for working through this!

@nikkimk nikkimk 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.

Since an infield button is only ever used in a field and not as a standalone component, the examples should show it used inside fields accessibly. This allows us to fully test for accessibility as well as model to our consumers how to use this component.

Agreed but this depends on swc-picker and swc-numberfield being visually ready. If I add a contrived wrapper that would misrepresent actual usage. I'd like to track this as a follow-up once those components are available. For now, the component's own accessibility contract is narrow by design: accessible-label maps to aria-label on the inner <button>, and tabindex="-1" keeps it out of the tab order. I've verified that contract is wired correctly.

Screenshot 2026-07-16 at 4 32 32 PM

The stories should use a dummy component in these examples to use an existing one anyway, because that shows the users how to implement it accessibly in their own code. See how the FocusgroupNavigationController and LiveSelectionController docs use stories that are not actual SWC components.

I won't be able to sign off without testing these in context.

Per review feedback: infield buttons are only ever used inside a form
field, so examples should model that real-world pattern accessibly.

- Overview: picker field (Country text input + chevron button)
- Anatomy: three field types (picker, search/clear, number stepper)
- Accessibility: same three field types for accurate a11y tree coverage

Field wrappers use a native <label>/<input> pair so axe and ARIA
snapshot tests can verify label association alongside button labels.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Rajdeepc
Rajdeepc force-pushed the rajdeepc/feat-infield-button-migration-phase-5 branch from 91a253a to 2b1bb29 Compare July 23, 2026 10:16
… 2 Figma

Extract a single renderField() template function shared by all three field
context helpers (picker, search, stepper). Wrapper uses padding:6px, stretch
alignment, and Spectrum token-based border/radius. Stepper places both buttons
on the trailing edge to match the Figma spec.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Rajdeepc

Rajdeepc commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Since an infield button is only ever used in a field and not as a standalone component, the examples should show it used inside fields accessibly. This allows us to fully test for accessibility as well as model to our consumers how to use this component.

Agreed but this depends on swc-picker and swc-numberfield being visually ready. If I add a contrived wrapper that would misrepresent actual usage. I'd like to track this as a follow-up once those components are available. For now, the component's own accessibility contract is narrow by design: accessible-label maps to aria-label on the inner <button>, and tabindex="-1" keeps it out of the tab order. I've verified that contract is wired correctly.
Screenshot 2026-07-16 at 4 32 32 PM

The stories should use a dummy component in these examples to use an existing one anyway, because that shows the users how to implement it accessibly in their own code. See how the FocusgroupNavigationController and LiveSelectionController docs use stories that are not actual SWC components.

I won't be able to sign off without testing these in context.

@nikkimk Make sense. I added some demo components to replicate the UI composition of this component. Let me know if this is fine or not.
https://swcpreviews.z13.web.core.windows.net/pr-6499/docs/gen2-storybook-prod/?path=/docs/components-infield-button--docs

@Rajdeepc
Rajdeepc requested a review from nikkimk July 23, 2026 11:12

@nikkimk nikkimk 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.

Thanks for taking this on. LTGM

@Rajdeepc
Rajdeepc merged commit 6ab7d29 into swc-2105/infield-button Jul 30, 2026
27 checks passed
@Rajdeepc
Rajdeepc deleted the rajdeepc/feat-infield-button-migration-phase-5 branch July 30, 2026 05:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gen2 These issues or PRs map to our 2nd generation work to modernizing infrastructure. 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