Skip to content

feat(button): support tooltip directly on button#3368

Draft
jpzwarte wants to merge 5 commits into
mainfrom
feature/3344-tooltip-property-on-button
Draft

feat(button): support tooltip directly on button#3368
jpzwarte wants to merge 5 commits into
mainfrom
feature/3344-tooltip-property-on-button

Conversation

@jpzwarte
Copy link
Copy Markdown
Member

@jpzwarte jpzwarte commented May 21, 2026

Closes #3344

Summary

Adds a tooltip property to sl-button that renders an <sl-tooltip> inside the button's shadow DOM and wires up the correct ARIA relationships automatically.

Previously, adding a tooltip to a button required adding a sibling <sl-tooltip> and setting aria-describedby / aria-labelledby by hand — especially cumbersome for icon-only buttons where the tooltip doubles as the accessible label.

<sl-button tooltip="Delete item">
  <sl-icon name="trash"></sl-icon>
</sl-button>

Behaviour

  • Icon-only buttons — tooltip acts as the accessible label (aria-labelledby).
  • Text buttons — tooltip acts as an accessible description (aria-describedby).
  • When aria-labelledby is also set on the host, both the external label element and the tooltip are preserved in ariaLabelledByElements on the inner <button>.

Changes

  • packages/components/button/src/button.ts — new tooltip property, scoped sl-tooltip in the render template, #forwardedLabelElements tracking, and #syncAriaLabelledBy() to merge forwarded label elements with the tooltip element after each render.
  • packages/components/button/src/button.spec.ts — unit tests covering render, text content, aria wiring for text and icon-only variants, removal, and the combined aria-labelledby + tooltip case.
  • .changeset/afraid-parents-nail.md — minor changeset for @sl-design-system/button.

Copilot AI review requested due to automatic review settings May 21, 2026 09:54
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 21, 2026

🦋 Changeset detected

Latest commit: 7979d82

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

This PR includes changesets to release 1 package
Name Type
@sl-design-system/button 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

@jpzwarte jpzwarte changed the title Add tooltip property to sl-button feat(button): support tooltip directly on button May 21, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 21, 2026

🕸 Storybook preview

You can view a preview here (commit 7979d8270c872a096b2af2b4468e8ad331fa53b2).

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a tooltip property to @sl-design-system/button (<sl-button>) so consumers can attach an <sl-tooltip> directly to the button and have ARIA relationships applied automatically, improving ergonomics especially for icon-only buttons.

Changes:

  • Added a new tooltip property to sl-button and render an internal <sl-tooltip> via scoped elements.
  • Wired tooltip-based ARIA (aria-describedby for text buttons, aria-labelledby for icon-only buttons) and added logic to merge forwarded aria-labelledby elements.
  • Added Storybook and unit test updates plus a changeset for a minor release.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
yarn.lock Updates workspace dependency metadata for the button package (adds tooltip/scoped-elements/lit entries).
packages/components/button/src/button.ts Implements the tooltip property, internal tooltip rendering, and ARIA wiring/merging logic.
packages/components/button/src/button.stories.ts Updates stories to demonstrate tooltip usage, including icon-only example.
packages/components/button/src/button.spec.ts Adds unit tests for tooltip rendering and ARIA behavior.
packages/components/button/package.json Adds @sl-design-system/tooltip dependency and declares scoped-elements/lit peer/dev dependencies.
.changeset/afraid-parents-nail.md Declares a minor release for the new tooltip API.

Comment on lines +208 to +216
// If the button is icon only, the tooltip functions as the label, otherwise it functions as the description.
let ariaLabelledBy: string | undefined, ariaDescribedBy: string | undefined;
if (this.tooltip) {
if (this.internals.states.has('icon-only')) {
ariaLabelledBy = 'tooltip';
} else {
ariaDescribedBy = 'tooltip';
}
}
Comment thread packages/components/button/src/button.ts
Comment on lines +186 to +190
// Capture any aria-labelledby elements the mixin just forwarded to the inner button.
this.#forwardedLabelElements = [
...((this.button as unknown as { ariaLabelledByElements: Element[] | null })
.ariaLabelledByElements ?? [])
];
Comment on lines 155 to 159
<p>
This example shows an icon-only button. When using an icon-only button, it's important to
provide an accessible name using the <code>aria-label</code> attribute so that assistive
technologies can convey the purpose of the button to users.
</p>
@jpzwarte jpzwarte marked this pull request as draft May 21, 2026 13:36
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 21, 2026

🕸 Website preview

You can view a preview here (commit 7979d8270c872a096b2af2b4468e8ad331fa53b2).

Copilot AI review requested due to automatic review settings May 21, 2026 13:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 9 changed files in this pull request and generated 5 comments.

Comment on lines +193 to 216
// If the button is icon only, the tooltip functions as the label, otherwise it functions as the description.
let ariaLabelledBy: string | undefined, ariaDescribedBy: string | undefined;
if (this.tooltip) {
if (this.internals.states.has('icon-only')) {
ariaLabelledBy = 'tooltip';
} else {
ariaDescribedBy = 'tooltip';
}
}

return html`
<button
@click=${this.#onClick}
aria-describedby=${ifDefined(ariaDescribedBy)}
aria-labelledby=${ifDefined(ariaLabelledBy)}
command=${ifDefined(this.command)}
.commandForElement=${target}
?disabled=${this.disabled}
part="button"
type="button">
<slot></slot>
</button>
${this.tooltip ? html`<sl-tooltip id="tooltip">${this.tooltip}</sl-tooltip>` : nothing}
`;
Comment on lines +720 to +727
it('should include both the tooltip and aria-labelledby element in ariaLabelledByElements', async () => {
const wrapper = await fixture(html`
<div>
<span id="icon-btn-label">Favorite star</span>
<sl-button aria-labelledby="icon-btn-label" tooltip="Mark as favorite">
Hello world
</sl-button>
</div>
super.willUpdate(changes);

if (changes.has('anchor') || changes.has('for')) {
this.#updateAnchor();
Comment on lines +85 to +88
if (this.anchor) {
this.#removeAriaRelation(this.anchor);
}

Comment on lines +1 to +20
import { CSSResultGroup, LitElement, PropertyValues, TemplateResult, html } from 'lit';
import { property, state } from 'lit/decorators.js';
import styles from './tooltip2.scss.js';

let nextUniqueId = 0;

const SHOW_DELAY = 150,
HIDE_DELAY = 0;

/**
* A tooltip component that can be used to display additional information about an element when the
* user hovers over it, focuses it, or clicks it. The tooltip is positioned relative to an anchor
* element, which can be specified using the `for` attribute.
*
* The tooltip will automatically determine the appropriate ARIA relation to use based on the `type`
* property. By default, it will use `ariaLabelledByElements`, but if `type` is set to
* `description`, it will use `ariaDescribedByElements` instead.
*/
export class Tooltip2 extends LitElement {
/** @internal */
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.

[Button] add a tooltip property to button

2 participants