diff --git a/1st-gen/packages/button/clear-button.md b/1st-gen/packages/button/clear-button.md
index 722e4a3651..2078d5d8a9 100644
--- a/1st-gen/packages/button/clear-button.md
+++ b/1st-gen/packages/button/clear-button.md
@@ -25,34 +25,21 @@ import { ClearButton } from '@spectrum-web-components/button';
### Anatomy
-The clear button is a button with only close icon.
+The clear button is a button with only a close icon.
```html
-Reset
+
```
#### Label
-The label for an `` element can be set via it's default slot or with the `label` attribute. With either method, the label will not be visible but still read by screen readers.
-
-
-Default slot
-
-
-```html demo
-Clear
-```
-
-
-Label attribute
-
+An accessible label for an `` must be provided using the `label` attribute. This sets the `aria-label` for screen readers. Unlike other button types, the clear button only displays an icon and does not render slot content, so the `label` attribute is the only way to provide an accessible name.
```html demo
-Clear
+
```
-
-
+The `label` attribute is required and will be set as the `aria-label` on the element.
### Options
@@ -63,7 +50,7 @@ The label for an `` element can be set via it's default slot or
```html demo
-Small
+
```
@@ -71,7 +58,7 @@ The label for an `` element can be set via it's default slot or
```html demo
-Medium
+
```
@@ -79,7 +66,7 @@ The label for an `` element can be set via it's default slot or
```html demo
-Large
+
```
@@ -87,7 +74,7 @@ The label for an `` element can be set via it's default slot or
```html demo
-Extra Large
+
```
@@ -119,8 +106,8 @@ While disabled, the `` element will not respond to click events
```html
- Normal
- Disabled
+
+
```
@@ -132,9 +119,10 @@ Events handlers for clicks and other user actions can be registered on a
`` as one would on a standard HTML `` element.
```html
-
- Click me
-
+
```
#### Autofocus
@@ -148,7 +136,7 @@ popover or dialog opens.
- Clear
+
```
@@ -157,4 +145,4 @@ popover or dialog opens.
#### Include a label
-A button is required to have either text in the default slot or a `label` attribute on the ``.
+A button is required to have a `label` attribute on the `` to provide an accessible name for screen readers. The `label` attribute sets the `aria-label` property, ensuring the button is properly announced to assistive technologies.
diff --git a/1st-gen/packages/button/src/ClearButton.ts b/1st-gen/packages/button/src/ClearButton.ts
index aeb75dced1..8bd805e4f9 100644
--- a/1st-gen/packages/button/src/ClearButton.ts
+++ b/1st-gen/packages/button/src/ClearButton.ts
@@ -55,7 +55,7 @@ const crossIcon: Record TemplateResult> = {
/**
* @element sp-clear-button
*
- * @slot - text label of the Clear Button
+ * @attr {string} label - Required accessible label set as aria-label
*/
export class ClearButton extends SizedMixin(StyledButton, {
noDefaultSize: true,
@@ -64,6 +64,14 @@ export class ClearButton extends SizedMixin(StyledButton, {
return [...super.styles, buttonStyles, crossMediumStyles];
}
+ /**
+ * An accessible label that describes the component.
+ * It will be applied to aria-label, but not visually rendered.
+ * This attribute is required for clear buttons.
+ */
+ @property()
+ public override label!: string;
+
@property({ type: Boolean, reflect: true })
public quiet = false;
@@ -121,4 +129,28 @@ export class ClearButton extends SizedMixin(StyledButton, {
${super.render()}
`;
}
+
+ public override connectedCallback(): void {
+ super.connectedCallback();
+
+ // Deprecation warning for default slot when content is provided
+ if (window.__swc.DEBUG && this.textContent?.trim()) {
+ window.__swc.warn(
+ this,
+ `The default slot for text content in <${this.localName}> has been deprecated and will be removed in a future release. The clear button is icon-only and does not render slot content. Use the "label" attribute instead to provide an accessible name.`,
+ 'https://opensource.adobe.com/spectrum-web-components/components/button/#clear-button',
+ { level: 'deprecation' }
+ );
+ }
+
+ // Warning for missing label attribute
+ if (window.__swc.DEBUG && !this.label) {
+ window.__swc.warn(
+ this,
+ `The "label" attribute is required on <${this.localName}> to provide an accessible name for screen readers. Please add a label attribute, e.g., <${this.localName} label="Clear">.`,
+ 'https://opensource.adobe.com/spectrum-web-components/components/button/#clear-button',
+ { level: 'high' }
+ );
+ }
+ }
}
diff --git a/1st-gen/packages/button/stories/template.ts b/1st-gen/packages/button/stories/template.ts
index 2f2f3f21fe..6339510eb2 100644
--- a/1st-gen/packages/button/stories/template.ts
+++ b/1st-gen/packages/button/stories/template.ts
@@ -16,6 +16,9 @@ import {
ButtonVariants,
} from '@spectrum-web-components/button/src/Button.js';
+import '@spectrum-web-components/button/sp-clear-button.js';
+import '@spectrum-web-components/button/sp-close-button.js';
+
export interface Properties {
staticColor?: 'white' | 'black';
variant?: ButtonVariants;
@@ -30,6 +33,7 @@ export interface Properties {
noWrap?: boolean;
iconOnly?: boolean;
label?: string;
+ componentName?: string;
}
export const Template = ({
@@ -38,14 +42,47 @@ export const Template = ({
size,
treatment,
variant,
-}: Properties): TemplateResult => html`
-
- Test Button
-
-`;
+ label = 'Clear',
+ quiet,
+ staticColor,
+ componentName,
+}: Properties): TemplateResult => {
+ // Render clear-button for clear-button docs
+ if (componentName === 'clear-button') {
+ return html`
+
+ `;
+ }
+
+ // Render close-button for close-button docs
+ if (componentName === 'close-button') {
+ return html`
+
+ `;
+ }
+
+ // Default: render standard button
+ return html`
+
+ Test Button
+
+ `;
+};
diff --git a/1st-gen/packages/button/test/clear-button.test.ts b/1st-gen/packages/button/test/clear-button.test.ts
index ceed72c87f..8b81a9cc55 100644
--- a/1st-gen/packages/button/test/clear-button.test.ts
+++ b/1st-gen/packages/button/test/clear-button.test.ts
@@ -15,7 +15,7 @@ import { ElementSize } from '@spectrum-web-components/base';
import { ClearButton } from '@spectrum-web-components/button';
import '@spectrum-web-components/button/sp-clear-button.js';
import { SinonStub, stub } from 'sinon';
-import { testForLitDevWarnings } from '../../../test/testing-helpers';
+import { testForLitDevWarnings } from '../../../test/testing-helpers.js';
describe('Clear Button', () => {
testForLitDevWarnings(async () =>
@@ -33,6 +33,40 @@ describe('Clear Button', () => {
});
});
+ it('has accessible name when label attribute is provided', async () => {
+ const el = await fixture(html`
+
+ `);
+
+ await elementUpdated(el);
+ expect(el.getAttribute('aria-label')).to.equal('Clear field');
+ await expect(el).to.be.accessible();
+ });
+
+ it('sets aria-label from label property', async () => {
+ const el = await fixture(html`
+
+ `);
+
+ await elementUpdated(el);
+ expect(el.hasAttribute('aria-label')).to.be.false;
+
+ el.label = 'Remove item';
+ await elementUpdated(el);
+ expect(el.getAttribute('aria-label')).to.equal('Remove item');
+ });
+
+ it('maintains accessible name in disabled state', async () => {
+ const el = await fixture(html`
+
+ `);
+
+ await elementUpdated(el);
+ expect(el.getAttribute('aria-label')).to.equal('Clear');
+ expect(el.hasAttribute('aria-disabled')).to.be.true;
+ await expect(el).to.be.accessible();
+ });
+
describe('dev mode', () => {
let consoleStub: SinonStub;
beforeEach(() => {
@@ -78,5 +112,45 @@ describe('Clear Button', () => {
expect(consoleStub).to.be.calledOnce;
expect(warning.includes(expectedContent)).to.be.true;
});
+
+ it('should log deprecation warning when slot content is provided', async () => {
+ const el = await fixture(html`
+ Clear
+ `);
+
+ await elementUpdated(el);
+
+ const warning = consoleStub.getCall(0).args.at(0);
+ const expectedContent =
+ 'The default slot for text content in has been deprecated';
+
+ expect(consoleStub).to.be.calledOnce;
+ expect(warning.includes(expectedContent)).to.be.true;
+ });
+
+ it('should log warning when label attribute is missing', async () => {
+ const el = await fixture(html`
+
+ `);
+
+ await elementUpdated(el);
+
+ const warning = consoleStub.getCall(0).args.at(0);
+ const expectedContent =
+ 'The "label" attribute is required on ';
+
+ expect(consoleStub).to.be.calledOnce;
+ expect(warning.includes(expectedContent)).to.be.true;
+ });
+
+ it('should not log warning when label attribute is provided without slot content', async () => {
+ const el = await fixture(html`
+
+ `);
+
+ await elementUpdated(el);
+
+ expect(consoleStub).to.not.be.called;
+ });
});
});
diff --git a/1st-gen/projects/documentation/content/_includes/partials/demo.njk b/1st-gen/projects/documentation/content/_includes/partials/demo.njk
index 1ed821f9a0..f8facbfe61 100644
--- a/1st-gen/projects/documentation/content/_includes/partials/demo.njk
+++ b/1st-gen/projects/documentation/content/_includes/partials/demo.njk
@@ -122,6 +122,8 @@
return args;
}
const renderDemo = (args = {}) => {
+ // Pass componentName to Template for variant detection
+ args.componentName = '{{ componentName }}';
render(Template(args), demo);
};
if (config) {