Skip to content

chore: migrate icon to core and second-gen#6012

Open
TarunAdobe wants to merge 14 commits intomainfrom
ttomar/second-gen-icons
Open

chore: migrate icon to core and second-gen#6012
TarunAdobe wants to merge 14 commits intomainfrom
ttomar/second-gen-icons

Conversation

@TarunAdobe
Copy link
Contributor

@TarunAdobe TarunAdobe commented Feb 6, 2026

Description

This PR introduces a minimal icon component for 2nd-gen in @adobe/swc, following the RFC direction.

It provides a consistent way for 2nd-gen components to render icons via:

  • Slotted inline SVG templates

It also adds a small shared icon template catalog under @adobe/swc/icon/elements to avoid per-component SVG duplication.

Motivation and context

This change unblocks migration of icon-dependent components to 2nd-gen without relying on 1st-gen icon packages and global iconset infrastructure.

The goal is to keep icon usage local, explicit, and consistent across 2nd-gen components.

Related issue(s)

  • RFC: minimal icon component for 2nd-gen

Screenshots (if appropriate)

N/A


Author's checklist

  • I have read the CONTRIBUTING and PULL_REQUESTS documents.
  • I have reviewed accessibility expectations for this feature.
  • I have added automated coverage for the icon behavior.
  • I have included a changeset if this change needs publishing.
  • I have updated relevant Storybook documentation/examples.

Reviewer's checklist

  • Scope aligns with RFC for minimal 2nd-gen icon support.
  • swc-icon behavior is correct for slot/SVG and src fallback.
  • Shared icon catalog exports are usable (@adobe/swc/icon/icons).
  • Automated tests cover expected behavior and pass in CI.
  • VRT/browser validation is completed as required.

Manual review test cases

  • Review swc-icon Storybook docs/examples

    1. Open icon docs in the PR Storybook build.
    2. Verify slotted SVG rendering works (default slot path).
    3. Verify shared template usage examples (Chevron100Icon, AlertIcon) render correctly.
    4. Inspect DOM to confirm:
      • Slotted SVG receives accessibility attributes as expected

Device review

  • Desktop
  • Emulated mobile
  • Emulated tablet

@changeset-bot
Copy link

changeset-bot bot commented Feb 6, 2026

⚠️ No Changeset found

Latest commit: fdcf5a7

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

@github-actions
Copy link
Contributor

github-actions bot commented Feb 6, 2026

📚 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-6012

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/second-gen-icons branch 4 times, most recently from 83fddc6 to 6ee05f1 Compare February 10, 2026 08:30
@TarunAdobe TarunAdobe marked this pull request as ready for review February 10, 2026 08:45
@TarunAdobe TarunAdobe requested a review from a team as a code owner February 10, 2026 08:45
@TarunAdobe TarunAdobe marked this pull request as draft February 10, 2026 13:49
@TarunAdobe TarunAdobe force-pushed the ttomar/second-gen-icons branch 2 times, most recently from 7cc0216 to 9e3aebd Compare February 20, 2026 06:32
@TarunAdobe TarunAdobe marked this pull request as ready for review February 20, 2026 06:34
@TarunAdobe TarunAdobe force-pushed the ttomar/second-gen-icons branch 2 times, most recently from cbc96d1 to f2ab00c Compare February 24, 2026 09:31
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you verify why this file is showing?

Copy link
Contributor

Choose a reason for hiding this comment

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

BLOCKING - can you verify, please?

// ──────────────────

/**
* Accessible label for the icon.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: we may want to work on these descriptions - we're pending some docs around this - but I imagine we'll want to be more descriptive in the future.

@TarunAdobe TarunAdobe force-pushed the ttomar/second-gen-icons branch from 1c0d556 to 03e29a9 Compare February 25, 2026 11:19
@TarunAdobe TarunAdobe force-pushed the ttomar/second-gen-icons branch 2 times, most recently from 7b89045 to 4973ade Compare March 2, 2026 10:12
Copy link
Contributor

@Rajdeepc Rajdeepc left a comment

Choose a reason for hiding this comment

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

Kindly add the ./components/icon export and typesVersions entry to core/package.json. This will fail for external consumers after build.

* Icon t-shirt size.
*/
@property({ reflect: true })
public size: IconSize = 'm';
Copy link
Contributor

Choose a reason for hiding this comment

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

Other 2nd-gen components uses SizedMixin

Copy link
Contributor Author

Choose a reason for hiding this comment

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

shoot. this was a big deal oops. got it right now

protected override updated(changedProperties: PropertyValues): void {
super.updated(changedProperties);
if (changedProperties.has('label')) {
this.updateSlottedIcon();
Copy link
Contributor

Choose a reason for hiding this comment

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

What about the initial render when a user provides

<swc-icon><svg>...</svg></swc-icon>

Can you override firstUpdated() to call updateSlottedIcon() and updateHostAccessibility() to ensure the initial state is correct regardless of property change timing. Also please think of using @queryAssignedElements instead of manually querying the slot.

@@ -0,0 +1,25 @@
/**
Copy link
Contributor

Choose a reason for hiding this comment

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

These are pure SVG template functions with no rendering layer dependency. Do you feel that we should move icon element templates to 2nd-gen/packages/core/components/icon/elements/ or a separate core/icons/ directory?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree the icon templates are conceptually “core-ish”, but right now they return Lit TemplateResult (html\``), so they still carry a rendering-layer dependency.

For this PR, I’d prefer to keep them under @adobe/spectrum-wc/icon/elements to avoid mixing concerns and expanding scope (move would also require export/typesVersions + import-path updates).

I’m happy to do a follow-up where we decide the long-term home (core/components/icon/elements vs core/icons) and, if needed, first make the templates rendering-agnostic so the move is clean.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm OK with keeping it simpler for now! But interestingly enough, I'd actually argue these may be part of the "rendering layer" - they are theme-specific, e.g. if we were to have a aether/components/icon/elements, these SVGs would be different.

};

export const Chevron100Icon = ({
direction = 'right',
Copy link
Contributor

Choose a reason for hiding this comment

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

This is the only icon which is using an inline style transform. There is an inconsistency. We can either make direction a concern of the swc-icon host via a CSS approach or we can document why Chevron is special.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the rationale here is that we don't want another component to control the icon css or how icon should render.. this should be isolated in the icon template literal itself and so optionally some icons can have these attributes like direction in this case. it was an intentional choice

Copy link
Contributor

@Rajdeepc Rajdeepc left a comment

Choose a reason for hiding this comment

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

Thanks for addressing the feedback. Added few suggestion but they are mostly trivial. Kindly check @adobe/spectrum-wc/icon/elements subpath issue then we can land this.

Comment on lines +17 to +18
import { Chevron100Icon } from '@adobe/spectrum-wc/icon/elements';
import * as iconElements from '@adobe/spectrum-wc/icon/elements';
Copy link
Contributor

Choose a reason for hiding this comment

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

Here * only matches a single path segment so @adobe/spectrum-wc/icon/elements would not resolve through ./*. This works in Storybook dev via the Vite resolve.alias but will fail for published customers.

import {
ICON_VALID_SIZES,
type IconSize,
} from '../../../../core/components/icon/Icon.types.js';
Copy link
Contributor

Choose a reason for hiding this comment

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

You can use absolute import here since export was added to core/package.json

Copy link
Contributor

Choose a reason for hiding this comment

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

Please do!

* All sizes are shown below for comparison.
*/
export const Sizes: Story = {
render: (_args) => html`
Copy link
Contributor

Choose a reason for hiding this comment

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

Please pass ..args here. You are ignoring it through prefixed with underscore. Storybook controls will not work.

render: (args) => html`
${ICON_VALID_SIZES.map(
(size) => html`
<swc-icon
Copy link
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 template? 😄

*/
export const Sources: Story = {
render: (args) => html`
<swc-icon
Copy link
Contributor

Choose a reason for hiding this comment

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

Template?

*/
export const SharedTemplates: Story = {
render: (args) => html`
<swc-icon
Copy link
Contributor

Choose a reason for hiding this comment

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

Same! Template wherever possible, please!

padding: 8px;
"
>
<swc-icon
Copy link
Contributor

Choose a reason for hiding this comment

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

(template)

*/
export const Accessibility: Story = {
render: (args) => html`
<swc-icon label=${ifDefined(args.label)} size=${ifDefined(args.size)}>
Copy link
Contributor

Choose a reason for hiding this comment

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

Last comment on the template! 😛

${catalog.map(
(entry) => html`
<div
style="
Copy link
Contributor

Choose a reason for hiding this comment

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

This is breaking the formatting, could we use Lit's styleMap for this, please?

padding: '8px',
} as const;

const renderIcon = (
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we may be talking past each other 😅 Maybe I'm missing what this does, but why do we need the renderIcon wrapper? Why can't we use template directly?
See the suggestions below


export const Overview: Story = {
tags: ['overview'],
render: (args) => renderIcon(args),
Copy link
Contributor

Choose a reason for hiding this comment

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

Without the renderIcon this could be:

Suggested change
render: (args) => renderIcon(args),
render: (args) => template(args, iconSvg),


export const Playground: Story = {
tags: ['autodocs', 'dev'],
render: (args) => renderIcon(args),
Copy link
Contributor

Choose a reason for hiding this comment

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

Without the renderIcon this could be:

Suggested change
render: (args) => renderIcon(args),
render: (args) => template(args, iconSvg),

* - Default slot: Provide SVG markup to render.
*/
export const Anatomy: Story = {
render: (args) => renderIcon(args, { label: 'Chevron icon' }),
Copy link
Contributor

Choose a reason for hiding this comment

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

Without the renderIcon this could be:

Suggested change
render: (args) => renderIcon(args, { label: 'Chevron icon' }),
render: (args) => template({ ...args, label: 'Chevron icon' }, iconSvg),

@TarunAdobe TarunAdobe force-pushed the ttomar/second-gen-icons branch from 611677c to 43451e7 Compare March 5, 2026 08:53
@TarunAdobe TarunAdobe force-pushed the ttomar/second-gen-icons branch from be01809 to 9e7bb1a Compare March 9, 2026 06:25
@TarunAdobe TarunAdobe force-pushed the ttomar/second-gen-icons branch from 9e7bb1a to fdcf5a7 Compare March 10, 2026 06:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants