Skip to content

feat(icon): make swc-icon public with BYO SVG docs and private elements catalog#6415

Open
TarunAdobe wants to merge 7 commits into
mainfrom
ttomar/icons-migration
Open

feat(icon): make swc-icon public with BYO SVG docs and private elements catalog#6415
TarunAdobe wants to merge 7 commits into
mainfrom
ttomar/icons-migration

Conversation

@TarunAdobe

@TarunAdobe TarunAdobe commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Description

Make <swc-icon> a public 2nd-gen component: public Storybook docs, consumer migration guide, and npm export
boundary, while keeping the internal elements/ SVG catalog monorepo-only.

Included in this PR

  • Contributor icon migration plan
  • Remove @status internal from swc-icon JSDoc and keep it aligned with other public 2nd-gen components
    (@since only)
  • Export Icon only from components/icon/index.ts so @adobe/spectrum-wc/icon stops leaking internal SVG
    factories
  • Public icon.stories.ts, icon.mdx, and migration-guide.mdx for a BYO SVG contract with no public
    elements/ import path
  • Trim icon.internal.* down to a maintainer-only catalog for dev Storybook
  • Fix conversational-ai pattern imports to use local relative elements/ paths instead of a public package
    path
  • Update swc-icon JSDoc examples to inline SVG only
  • Add a changeset for @adobe/spectrum-wc
  • Update 2nd-gen button docs and stories to prefer <swc-icon slot="icon">...</swc-icon> in icon-slot
    examples, matching the intended public icon path

Motivation and context

<swc-icon> already exists in 2nd-gen and is used internally by components and patterns, but it is still
treated like an internal implementation detail. Consumers migrating from <sp-icon> need a documented public
wrapper whose contract is simple: slot your own SVG.

This PR makes that public contract explicit.

It does not turn the internal elements/ SVG catalog into a public icon registry. Those factories remain a
maintainer convenience for SWC development only.

It also aligns button docs with that direction so 2nd-gen documentation points consumers toward swc-icon
instead of encouraging raw slotted SVG as the primary path.

Related issue(s)

  • N/A

Screenshots

N/A. This is primarily a docs, Storybook, and package export-boundary change.

Author's checklist

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

  • Public icon docs (production Storybook build)

    1. Run yarn storybook:build in 2nd-gen/packages/swc
    2. Open the Icon docs page under Components
    3. Expect: Overview, Sizes, Anatomy, Accessibility all render from the public docs/stories
    4. Expect: examples show <swc-icon> with slotted inline SVG
    5. Expect: no "Shared templates", "Available icons", or elements/ import guidance on the public page
  • Internal catalog (dev Storybook only)

    1. Run yarn storybook in 2nd-gen/packages/swc
    2. Open Icon / Internal catalog
    3. Expect: maintainer catalog and elements/ reference still exist locally in dev Storybook
  • Consumer migration guide

    1. Open Icon → Migration guide in Storybook
    2. Expect: sp-iconswc-icon, slot your own SVG, and no public @adobe/spectrum-wc/.../elements import
      path
    3. Expect: breaking changes documented (name, src, xxs / xxl, --mod-icon-*)
  • Package export boundary

    1. Confirm components/icon/index.ts exports Icon only
    2. Confirm @adobe/spectrum-wc/icon does not re-export Chevron100Icon or other internal factories
    3. Confirm internal component/pattern usage still resolves via local relative elements/ imports
  • Button docs alignment

    1. Open Button docs in Storybook
    2. Expect: icon-slot guidance prefers <swc-icon> as the documented path
    3. Expect: anatomy and migration examples use <swc-icon slot="icon">...</swc-icon>
  • Downstream patterns

    1. Open conversational-ai pattern stories that use chevrons
    2. Expect: no @adobe/spectrum-wc/icon/elements imports in source
    3. Expect: icons still render correctly

Device review

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

Accessibility testing checklist

Icon a11y behavior is unchanged: slotted SVG receives image semantics when label is provided, and decorative
usage remains hidden from the accessibility tree when no label is present. Re-verify on the public docs
stories.

  • Keyboard

    1. Open Icon → Accessibility in Storybook
    2. Tab through the page
    3. Expect: <swc-icon> is not focusable and does not create stray focus stops
  • Screen reader

    1. Open a labelled icon example and a decorative icon example
    2. With VoiceOver or NVDA, inspect the labelled icon
    3. Expect: labelled icon is announced as an image with its provided name
    4. Expect: decorative icon with no label is hidden from the accessibility tree

@changeset-bot

changeset-bot Bot commented Jun 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 63e87b5

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

This PR includes changesets to release 1 package
Name Type
@adobe/spectrum-wc Minor

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 Jun 17, 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-6415

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.

@TarunAdobe TarunAdobe force-pushed the ttomar/icons-migration branch from a9752d9 to 919bf1d Compare June 22, 2026 07:51
@TarunAdobe TarunAdobe marked this pull request as ready for review June 22, 2026 07:53
@TarunAdobe TarunAdobe requested a review from a team as a code owner June 22, 2026 07:53
@coveralls

coveralls commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 28080828176

Coverage remained the same at 96.246%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 39173
Covered Lines: 37902
Line Coverage: 96.76%
Relevant Branches: 6460
Covered Branches: 6018
Branch Coverage: 93.16%
Branches in Coverage %: Yes
Coverage Strength: 458.96 hits per line

💛 - Coveralls

@TarunAdobe TarunAdobe force-pushed the ttomar/icons-migration branch from 919bf1d to f021bc4 Compare June 22, 2026 13:26
} as const satisfies Record<ButtonStaticColor, string>;

const addIconSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" aria-hidden="true" focusable="false"><path d="M31.5 17H19V4.5a1 1 0 0 0-2 0V17H4.5a1 1 0 0 0 0 2H17v12.5a1 1 0 0 0 2 0V19h12.5a1 1 0 0 0 0-2z"/></svg>`;
const addIconSvg = `<swc-icon slot="icon" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" aria-hidden="true" focusable="false"><path d="M31.5 17H19V4.5a1 1 0 0 0-2 0V17H4.5a1 1 0 0 0 0 2H17v12.5a1 1 0 0 0 2 0V19h12.5a1 1 0 0 0 0-2z"/></svg></swc-icon>`;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

aria-hidden appears both on swc-icon and on the svg element, is that intentional?

It also appears in the svg for the Anatomy story below.

label: 'Expand',
size: 'm',
},
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It would be cool to add a control to the playground to be able to change the svg, I think we can add one that allows you to add your own svg code.

<!-- After -->
<swc-button accessible-label="Add item">
<svg slot="icon">...</svg>
<swc-icon slot="icon" aria-hidden="true">

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

aria-hidden is also being set here, I'm not sure it's necessary

// PLAYGROUND STORY
// ────────────────────

export const Playground: Story = {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It would be cool if this internal icon Playground featured a select menu of available icons

- Always provide a descriptive `label` for informative icons
- Use empty labels only for purely decorative icons
- Keep labels short and specific (e.g., "Expand" instead of "Icon")
- When an icon accompanies visible text, omit `label` and set `aria-hidden="true"` on the icon so screen readers do not announce duplicate content

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This contradicts L59:

  • When no label is provided, slotted SVGs are marked aria-hidden="true"

@TarunAdobe

Copy link
Copy Markdown
Contributor Author

@rise-erpelding Addressed these in follow-up: removed the manual aria-hidden guidance/examples so decorative usage now relies on omitting label, which matches the component behavior; added a public Playground SVG control so consumers can try their own inline markup; and added an internal icon-name select for the maintainer catalog Playground.

@TarunAdobe TarunAdobe force-pushed the ttomar/icons-migration branch 2 times, most recently from 882b91f to 7018e68 Compare June 23, 2026 08:32
</swc-icon>
```

**With Lit:**

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'm not sure what to think about this block. We say "with lit", but it could be with any templating language / vanilla HTML too.

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

Looks good, but I feel like the internal documentation needs a bit of cleanup 😄

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.

This now shows like this:

Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

just this one cleanup right? everything else looks pretty minimal to me...

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

For discussion: should components like Button and Badge automatically assign the corresponding size attribute to the icon, or accept whatever icon size a consumer adds? Can be a follow-up, if changes are needed.

Comment thread 2nd-gen/packages/swc/components/icon/icon.mdx Outdated
Comment thread 2nd-gen/packages/swc/components/icon/icon.mdx Outdated
Comment thread 2nd-gen/packages/swc/components/icon/icon.mdx Outdated
Comment thread 2nd-gen/packages/swc/components/badge/Badge.ts Outdated
Comment thread 2nd-gen/packages/swc/components/badge/migration-guide.mdx Outdated
Comment thread 2nd-gen/packages/swc/components/badge/migration-guide.mdx Outdated
Comment thread 2nd-gen/packages/swc/components/button/stories/button.stories.ts Outdated
Comment thread 2nd-gen/packages/swc/components/button/stories/button.stories.ts Outdated
@TarunAdobe

Copy link
Copy Markdown
Contributor Author

Thanks for the thoughtful review @5t3ph, I addressed the icon docs/accessibility updates in this PR:

• Updated icon.mdx sizing guidance to emphasize matching component sizes (removed per-size use-case descriptions).
• Clarified SVG source guidance to keep xmlns/viewBox and omit width/height so size controls dimensions.
• Updated guidance from “empty label” to “omit label” for decorative icons.
• Replaced Lit-specific wording in the migration guide with template-agnostic wording.
• Added focusable="false" handling to IconBase when label is omitted (alongside aria-hidden), and covered this in icon tests.
• Removed manual aria-hidden usage from updated badge/button icon examples/docs so they rely on swc-icon behavior consistently.

As for the should components like Button and Badge automatically assign the corresponding size attribute to the icon, or accept whatever icon size a consumer adds? This need a broader discussion outside of this PR's scope

TarunAdobe and others added 7 commits June 24, 2026 12:23
Document go-public scope and remove @status internal from swc-icon JSDoc.

Co-authored-by: Cursor <cursoragent@cursor.com>
Document concrete how-to for export boundary, docs split, and ship checklist.

Co-authored-by: Cursor <cursoragent@cursor.com>
Ship public Icon docs, stories, migration guide, and tests while keeping
the elements catalog internal. Update pattern imports and badge/tabs
migration docs to show the swc-icon wrapper pattern.

Co-authored-by: Cursor <cursoragent@cursor.com>
Apply reviewer feedback by removing manual aria-hidden usage in icon slot examples,
clarifying icon sizing guidance, and managing decorative SVG focusability in IconBase.

Co-authored-by: Cursor <cursoragent@cursor.com>
Drop the generated type-import guidance and subclassing caution
from the migrated getting-started block.

Co-authored-by: Cursor <cursoragent@cursor.com>
@TarunAdobe TarunAdobe force-pushed the ttomar/icons-migration branch from 21f8b3d to 63e87b5 Compare June 24, 2026 06:53
@5t3ph 5t3ph added Component:Icon Status:Ready for review PR ready for review or re-review. labels Jun 24, 2026
@5t3ph 5t3ph added 2nd gen These issues or PRs map to our 2nd generation work to modernizing infrastructure. run_vrt Triggers the Chromatic VRT run for 2nd-gen labels Jun 24, 2026
Comment on lines -62 to -68
To reference the \`${baseClassName}\` type, import it as a type-only import:

\`\`\`typescript
import type { ${baseClassName} } from '@adobe/spectrum-wc/components/${packageName}';
\`\`\`

> The class is exposed primarily for type purposes. Extending it is possible, but the internal shape is not part of the public API — if you choose to subclass, you do so at your own risk and may need to adjust your code between releases.

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 is this being removed?


When an icon accompanies a text label, the icon is decorative and should be hidden from assistive technology.
Apply `aria-hidden="true"` to the `<swc-icon>` so screen readers only announce the label text.
Omit `label` on `<swc-icon>` so screen readers only announce the label text.

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.

This reads confusing. should it saw "so screen readers only announce badge label text"?

* <swc-badge variant="neutral" fixed="fill">
* <sp-icon-checkmark slot="icon"></sp-icon-checkmark>
* <swc-icon slot="icon">
* <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">...</svg>

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 use the approved adobe checkmark icon?

<swc-badge aria-label="Approved">
<sp-icon-checkmark-circle slot="icon"></sp-icon-checkmark-circle>
<swc-icon slot="icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10">...</svg>

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 use only approved Adobe icons throughout?

| `--mod-icon-*` custom properties | `--swc-icon-*` equivalents (see [Styling](#styling)) |
| Removed | Replacement |
| -------------------------------- | -------------------------------------------------------------------------------------------------- |
| `name` attribute | Slot an inline `<svg>`. See [step 2](#2-replace-name-or-src-with-slotted-svg) |

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 think the icon factory function call out still remains true since that is what A4U ships if im not mistaken

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

This has a number of a11y issues and is missing the a11y migration plan before proceeding.

@nikkimk nikkimk self-requested a review June 24, 2026 16:44

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

Can we please back up so I can do an a11y migration analysis on icon and update the migration plan accordingly?

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.

there are other issues in this file that are overriding a hosts role and that should not be happening. @nikkimk is gonna do a fully a11y review like other migrations to call out the correct behavior.

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

Enhancements to add:

  • remove detected width and height attributes from the SVG (otherwise, prevents our size styling from working)
  • add this attribute and value to SVG if missing: xmlns="http://www.w3.org/2000/svg"
  • add warnings if the SVG does not have a viewBox attribute

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

Labels

2nd gen These issues or PRs map to our 2nd generation work to modernizing infrastructure. Component:Icon run_vrt Triggers the Chromatic VRT run for 2nd-gen Status:Ready for review PR ready for review or re-review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants