Skip to content

fix(suggestion-group): update suggestion group heading semantics#6224

Open
TarunAdobe wants to merge 3 commits into
mainfrom
ttomar/suggestion-group-heading
Open

fix(suggestion-group): update suggestion group heading semantics#6224
TarunAdobe wants to merge 3 commits into
mainfrom
ttomar/suggestion-group-heading

Conversation

@TarunAdobe
Copy link
Copy Markdown
Contributor

fix(suggestion-group): require heading slot and prioritize accessible-label

Description

This PR updates suggestion group semantics and accessibility behavior:

  1. Uses required consumer-provided heading content via slot="heading" instead of fixed internal heading semantics.
  2. Makes accessible-label the accessible-name override when provided.
  3. Removes forced heading typography from slotted heading content and keeps layout normalization only.
  4. Updates stories/examples and tests to align with the new contract and labeling precedence.

Motivation and context

We want suggestion group to behave as a true composition primitive:

  • Consumers own heading semantics.
  • Consumers own heading styling.
  • Accessible naming priority is predictable and explicit.

This avoids hardcoded semantics and prevents component styles from overriding consumer heading intent.

Related issue(s)

  • fixes [Issue Number]

Screenshots (if appropriate)

N/A (behavioral/API and docs-focused change)


Author's checklist

  • I have read the CONTRIBUTING and PULL_REQUESTS documents.
  • I have reviewed at 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

  • Heading semantics are consumer-controlled

    1. Go to Storybook: Conversational AI / Suggestion group / Heading.
    2. Compare examples using h3 and h2 in slot="heading".
    3. Expect semantic element to be consumer-provided and rendered as-is.
  • Accessible label precedence over heading

    1. Go to Storybook suggestion-group Playground/Accessibility scenario.
    2. Provide both a heading slot and accessible-label="Custom suggestions label".
    3. Expect group to use aria-label="Custom suggestions label" and not use heading-based labeling.
  • No forced heading typography from component

    1. Go to Storybook: Conversational AI / Suggestion group / Heading.
    2. Inspect heading rendering and applied styles.
    3. Expect no component-imposed heading typography; only layout normalization remains.
  • Related conversational usage remains stable

    1. Go to Storybook:
      • Conversational AI / System message / Playground
      • Conversational AI / Conversation thread / Playground
    2. Verify suggestion group heading appears correctly and items remain interactive.
    3. Expect no regressions in behavior.

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) — What to test for: Focus order is logical; Tab reaches the component and all interactive descendants; Enter/Space activate where appropriate; arrow keys work for tabs, menus, sliders, etc.; no focus traps; Escape dismisses when applicable; focus indicator is visible.

    1. Go to Storybook: Conversational AI / Suggestion group / Overview.
    2. Use Tab to move through suggestion items; activate with Enter and Space.
    3. Expect logical focus order, visible focus indication, and correct activation behavior.
  • Screen reader (required — document steps below) — What to test for: Role and name are announced correctly; state changes (e.g. expanded, selected) are announced; labels and relationships are clear; no unnecessary or duplicate announcements.

    1. Go to Storybook: Conversational AI / Suggestion group / Accessibility.
    2. Test with heading slot only, then with accessible-label.
    3. Expect group name to come from heading when no override is provided, and from accessible-label when present.

@TarunAdobe TarunAdobe requested a review from a team as a code owner April 30, 2026 09:21
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 30, 2026

⚠️ No Changeset found

Latest commit: 548603f

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
Copy Markdown
Contributor

github-actions Bot commented Apr 30, 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-6224

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.

const fallbackLabel =
this.accessibleLabel.trim().length > 0
? this.accessibleLabel.trim()
: 'Follow-up suggestions';
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.

i can do a follow up PR converting this logic into a shared util for all components if possible :)

Comment on lines 333 to 339
[
'Accordion',
[
'Accessibility migration analysis',
'Rendering and styling migration analysis',
],
'Action button',
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.

this is coming after recent merge of accordion to main???! not sure do we wanna fix it here or i remove it?

@TarunAdobe TarunAdobe force-pushed the ttomar/suggestion-group-heading branch 2 times, most recently from 74c5186 to c409178 Compare May 5, 2026 09:07
@TarunAdobe TarunAdobe self-assigned this May 5, 2026
@TarunAdobe TarunAdobe added the Status:Ready for review PR ready for review or re-review. label May 5, 2026
@TarunAdobe TarunAdobe force-pushed the ttomar/suggestion-group-heading branch from c409178 to 548603f Compare May 6, 2026 10:36
@TarunAdobe TarunAdobe changed the title chore: fix suggestion group heading fix(suggestion-group): update suggestion group heading semantics May 7, 2026
${text}
</h3>
`;
private _getHeadingElement(): HTMLElement | null {
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.

do we really need this function? we could literally just read this._assignedHeadingElements[0] wherever


protected override updated(_changedProperties: PropertyValues<this>): void {
super.updated(_changedProperties);
this._ensureHeadingId();
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.

do we need this here? the slotchangehandler is already doing this. we could prob get rid of the function then

const accessibleLabel = this.accessibleLabel.trim();
const hasAccessibleLabel = accessibleLabel.length > 0;

if (!hasHeading && !hasAccessibleLabel) {
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.

hmmm, this is interesting. rn you're running this after ensureHeadingId so this is always true. Depending on your refactor from the other comments, please check.

hasHeading ? 'swc-suggestion-group-heading' : undefined
)}
>
<div class="swc-SuggestionGroup-title" ?hidden=${!hasHeading}>
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.

hmmm this is not great... on the first render hasHeading is false and the title div gets hidden. Then updated() triggers a second render that flips it, this is probably gonna cause some flash... you can either skip the ?hidden binding and use CSS to handle the no-heading case instead (e.g. :empty)

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 is a double paint. Good catch!

'parent exposes heading and group labeling on the host (not inner shadow nodes)',
async () => {
await group.updateComplete;
await Promise.resolve();
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.

what is this? updateComplete, resolve, updatecomplete? 😅

Comment on lines +119 to +120
this._ensureHeadingId();
this._syncHostGroupSemantics();
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 runs on every update. Put a guard

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

Labels

snapshot-release 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