Skip to content

feat(a2ui): render real Material Symbols icons (not the name as text)#720

Open
blove wants to merge 2 commits into
mainfrom
claude/a2ui-material-symbols-icons
Open

feat(a2ui): render real Material Symbols icons (not the name as text)#720
blove wants to merge 2 commits into
mainfrom
claude/a2ui-material-symbols-icons

Conversation

@blove

@blove blove commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Summary

The a2ui catalog Icon component rendered the icon name as literal text (a spec with Icon { name: "trending_up" } showed the string "trending_up"). This makes it render the actual glyph, aligned with the canonical A2UI renderer, which uses Material Symbols — the name is a Material Symbols ligature.

Changes

  • a2ui-icon now outputs the name into a material-symbols-outlined-classed span and carries the Material Symbols Outlined font rules in its own styles (so it depends only on the @font-face, not a global helper class). currentColor (theme-aware) + size via font-size. Renders nothing when there's no name.
  • Demos load the font: the Material Symbols Outlined stylesheet is added to the <head> of the 4 a2ui demos (examples/chat, examples/ag-ui, cockpit/chat/a2ui, cockpit/ag-ui/a2ui). The library injects no web fontlibs/chat/README.md documents the requirement for consumers (standard for icon fonts).
  • No backend prompt change: the LLM keeps emitting Material Symbols names; valid names render, unknown/not-yet-loaded names fall back to plain text.

Verification

  • nx run-many -t test lint build --projects=chat — green.
  • All 4 a2ui demo apps build — green.
  • Visual smoke: rendered the exact markup the component emits with the demo's font link in a real browser — the ligature names render as glyphs (first icon measures 24×24, not the ~120px-wide raw text); screenshot in the PR thread.
  • No a2ui e2e asserts on icon text, so switching to glyphs breaks nothing.

Spec: docs/superpowers/specs/2026-06-20-a2ui-material-symbols-icons-design.md

🤖 Generated with Claude Code

blove added 2 commits June 19, 2026 19:36
… the name as text)

Aligns the a2ui catalog Icon with the canonical A2UI renderer: the icon name
is a Material Symbols ligature rendered via the Material Symbols Outlined font
(currentColor, size prop). The library injects no web font; the a2ui demos load
the Material Symbols stylesheet in index.html and the README documents the
requirement for consumers. Unknown/unloaded names fall back gracefully.
@vercel

vercel Bot commented Jun 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
threadplane Ready Ready Preview, Comment Jun 20, 2026 3:17am

Request Review

@github-actions github-actions Bot 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.

Automated approval: this PR received an intelligent (AI) code review. See the review comments on this PR.

@blove blove enabled auto-merge (squash) June 20, 2026 02:41
@github-actions

github-actions Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 1m 54s —— View job


Code Review

  • Gather context
  • Read changed files and diff
  • Analyze for correctness, security, type safety, Angular/RxJS issues
  • Post findings

The implementation is correct and well-structured. Two findings:

Missing tests (medium) — The spec doc (docs/superpowers/specs/2026-06-20-a2ui-material-symbols-icons-design.md §4) explicitly called for updating icon.component.spec.ts to assert the new class, text content, and font-size — but the test file was not touched. The only existing assertion is expect(A2uiIconComponent).toBeDefined(). Three cases would cover the change:

  • name provided → span has material-symbols-outlined class, text content equals the name
  • size input set → font-size equals ${size}px
  • no name → no span rendered (the @if guard)

Fix this →

word-wrap deprecated (minor) — see inline comment on icon.component.ts:30. Functionally equivalent but overflow-wrap is the CSS standard.

Everything else looks good: @if guard for empty name, role="img" + aria-label accessibility pattern, currentColor for theme-awareness, font-variation-settings defaults, the README consumer documentation, and keeping the library CDN-free while patching the four demo index.html files are all correct calls.

line-height: 1;
letter-spacing: normal;
text-transform: none;
white-space: nowrap;

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.

word-wrap is a deprecated alias; the standard property is overflow-wrap. Functionally equivalent today but worth aligning with the spec.

Suggested change
white-space: nowrap;
overflow-wrap: normal;

<span
class="a2ui-icon material-symbols-outlined"
[style.font-size]="size() ? size() + 'px' : '1.125rem'"
[attr.aria-label]="name"

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 span has both visible text content ({{ name }}) and aria-label. Per the ARIA spec, aria-label overrides text content for role="img", so screen readers announce the icon name cleanly without speaking the ligature text — this is correct. Just noting it explicitly since it can look redundant at first glance.

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.

1 participant