Skip to content

Commit

Permalink
feat: support aria-label attribute on Place Field Link
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 577327511
  • Loading branch information
mcreinhard authored and copybara-github committed Oct 27, 2023
1 parent b69d8bd commit 84bf6c9
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 7 deletions.
7 changes: 7 additions & 0 deletions src/icon_button/icon_button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,13 @@ export class IconButton extends BaseComponent {
`;
}

protected override updated() {
// If the aria-label attribute is set, hide it from the a11y tree. Otherwise
// the component and its shadow DOM content show up as duplicate nodes with
// the same aria-label.
this.role = this.ariaLabel != null ? 'none' : null;
}

private renderContent() {
const icon = this.icon ||
(!this.hasLabel || this.condensed ? DEFAULT_ICON : undefined);
Expand Down
9 changes: 9 additions & 0 deletions src/icon_button/icon_button_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,13 @@ describe('IconButton', () => {
expect(el.variant).toBe('outlined');
expect(el.getAttribute('variant')).toBe('outlined');
});

it('sets role="none" on the host when aria-label is present', async () => {
const el = await prepareState(html`
<gmpx-icon-button aria-label="enter">
</gmpx-icon-button>
`);

expect(el.role).toBe('none');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ export class PlaceDirectionsButton extends PlaceDataConsumer {
`;
}

protected override updated() {
// If the aria-label attribute is set, hide it from the a11y tree. Otherwise
// the component and its shadow DOM content show up as duplicate nodes with
// the same aria-label.
this.role = this.ariaLabel != null ? 'none' : null;
}

/** @ignore */
getRequiredFields(): Array<keyof Place> {
return ['displayName', 'formattedAddress', 'location'];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,16 @@ describe('PlaceDirectionsButton', () => {
expectedQuery}`);
});
});

it('sets role="none" on the host when aria-label is present', async () => {
const root = env.render(html`
<gmpx-place-directions-button aria-label="Get Directions">
</gmpx-place-directions-button>
`);
await env.waitForStability();
const el = root.querySelector<PlaceDirectionsButton>(
'gmpx-place-directions-button')!;

expect(el.role).toBe('none');
});
});
11 changes: 6 additions & 5 deletions src/place_building_blocks/place_field_link/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ import { PlaceFieldLink } from '@googlemaps/extended-component-library/place_bui

## Attributes and properties

| Attribute | Property | Property type | Description | Default | [Reflects?](https://open-wc.org/guides/knowledge/attributes-and-properties/#attribute-and-property-reflection) |
| ------------ | ----------- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------- |
| `href-field` | `hrefField` | `LinkField` | The field to link to, formatted as it is on either a `Place` or `PlaceResult`.<br/><br/>Allowed fields are: `googleMapsURI` or `url` for a link to this place on Google Maps; `websiteURI` or `website` for a link to this place's website. | `'websiteURI'` ||
| | `place` | `Place\|PlaceResult\|null\|undefined` | Place data to render, overriding anything provided by context. | ||
| `no-data` | `noData` | `boolean` | This read-only property and attribute indicate whether the component has the required Place data to display itself.<br/><br/>Use the attribute to target CSS rules if you wish to hide this component, or display alternate content, when there's no valid data. | `true` ||
| Attribute | Property | Property type | Description | Default | [Reflects?](https://open-wc.org/guides/knowledge/attributes-and-properties/#attribute-and-property-reflection) |
| ------------ | ----------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------- | -------------------------------------------------------------------------------------------------------------- |
| `href-field` | `hrefField` | `LinkField` | The field to link to, formatted as it is on either a `Place` or `PlaceResult`.<br/><br/>Allowed fields are: `googleMapsURI` or `url` for a link to this place on Google Maps; `websiteURI` or `website` for a link to this place's website. | `'websiteURI'` ||
| `aria-label` | `ariaLabel` | `string\|null` | The link description that gets read by assistive technology.<br/><br/>Set this to something more descriptive if the link's purpose isn't clear from its text content alone. For example, if the link text is just "Website", then the `aria-label` could be "Website for (business name)". | `null` ||
| | `place` | `Place\|PlaceResult\|null\|undefined` | Place data to render, overriding anything provided by context. | ||
| `no-data` | `noData` | `boolean` | This read-only property and attribute indicate whether the component has the required Place data to display itself.<br/><br/>Use the attribute to target CSS rules if you wish to hide this component, or display alternate content, when there's no valid data. | `true` ||

## Styling

Expand Down
22 changes: 20 additions & 2 deletions src/place_building_blocks/place_field_link/place_field_link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import {css, html} from 'lit';
import {css, html, nothing} from 'lit';
import {customElement, property} from 'lit/decorators.js';
import {when} from 'lit/directives/when.js';

Expand Down Expand Up @@ -92,11 +92,22 @@ export class PlaceFieldLink extends PlaceDataConsumer {
@property({type: String, reflect: true, attribute: 'href-field'})
hrefField: LinkField = 'websiteURI';

/**
* The link description that gets read by assistive technology.
*
* Set this to something more descriptive if the link's purpose isn't clear
* from its text content alone. For example, if the link text is just
* "Website", then the `aria-label` could be "Website for (business name)".
*/
@property({attribute: 'aria-label', reflect: true, type: String})
override ariaLabel: string|null = null;

protected override render() {
const href = this.getHref();
// clang-format off
return html`${when(href, () => html`
<a target="_blank" rel="noopener noreferrer" href=${href!}>
<a target="_blank" rel="noopener noreferrer" href=${href!}
aria-label=${this.ariaLabel ?? nothing}>
${when(this.hasContentForSlot(),
() => html`<slot></slot>`,
() => html`${this.getDefaultLinkText(href!)}`,
Expand All @@ -106,6 +117,13 @@ export class PlaceFieldLink extends PlaceDataConsumer {
// clang-format on
}

protected override updated() {
// If the aria-label attribute is set, hide it from the a11y tree. Otherwise
// the component and its shadow DOM content show up as duplicate nodes with
// the same aria-label.
this.role = this.ariaLabel != null ? 'none' : null;
}

/** @ignore */
getRequiredFields(): Array<keyof Place> {
return [toPlaceLinkField(this.hrefField)];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,33 @@ describe('PlaceFieldLink', () => {

expect(getHref(el)).toBe('https://www.mywebsite.com/');
});

it(`forwards aria-label to the anchor element`, async () => {
const [el] = await prepareState(html`
<gmpx-place-field-link .place=${fakePlace} aria-label="My Label">
</gmpx-place-field-link>
`);

const anchor = el.renderRoot.querySelector('a')!;
expect(anchor.getAttribute('aria-label')).toBe('My label');
});

it(`omits aria-label from the anchor element when not set`, async () => {
const [el] = await prepareState(html`
<gmpx-place-field-link .place=${fakePlace}>
</gmpx-place-field-link>
`);

const anchor = el.renderRoot.querySelector('a')!;
expect(anchor.hasAttribute('aria-label')).toBeFalse();
});

it('sets role="none" on the host when aria-label is present', async () => {
const [el] = await prepareState(html`
<gmpx-place-field-link .place=${fakePlace} aria-label="My Label">
</gmpx-place-field-link>
`);

expect(el.role).toBe('none');
});
});

0 comments on commit 84bf6c9

Please sign in to comment.