Skip to content

Commit

Permalink
fix rating a11y
Browse files Browse the repository at this point in the history
  • Loading branch information
claviska committed Aug 11, 2022
1 parent 578a580 commit c94db27
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 18 deletions.
50 changes: 34 additions & 16 deletions docs/components/rating.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,93 +5,107 @@
Ratings give users a way to quickly view and provide feedback.

```html preview
<sl-rating></sl-rating>
<sl-rating label="Rating"></sl-rating>
```

```jsx react
import { SlRating } from '@shoelace-style/shoelace/dist/react';

const App = () => <SlRating />;
const App = () => <SlRating label="Rating" />;
```

## Examples

### Labels

Ratings are commonly identified in context, so a visual label isn't typically necessary. However, you should always provide a label for assistive devices.

```html preview
<sl-rating label="Rate this component"></sl-rating>
```

```jsx react
import { SlRating } from '@shoelace-style/shoelace/dist/react';

const App = () => <SlRating label="Rate this component" />;
```

### Maximum Value

Ratings are 0-5 by default. To change the maximum possible value, use the `max` attribute.

```html preview
<sl-rating max="3"></sl-rating>
<sl-rating label="Rating" max="3"></sl-rating>
```

```jsx react
import { SlRating } from '@shoelace-style/shoelace/dist/react';

const App = () => <SlRating max={3} />;
const App = () => <SlRating label="Rating" max={3} />;
```

### Precision

Use the `precision` attribute to let users select fractional ratings.

```html preview
<sl-rating precision="0.5" value="2.5"></sl-rating>
<sl-rating label="Rating" precision="0.5" value="2.5"></sl-rating>
```

```jsx react
import { SlRating } from '@shoelace-style/shoelace/dist/react';

const App = () => <SlRating precision={0.5} value={2.5} />;
const App = () => <SlRating label="Rating" precision={0.5} value={2.5} />;
```

## Symbol Sizes

Set the `--symbol-size` custom property to adjust the size.

```html preview
<sl-rating style="--symbol-size: 2rem;"></sl-rating>
<sl-rating label="Rating" style="--symbol-size: 2rem;"></sl-rating>
```

```jsx react
import { SlRating } from '@shoelace-style/shoelace/dist/react';

const App = () => <SlRating style={{ '--symbol-size': '2rem' }} />;
const App = () => <SlRating label="Rating" style={{ '--symbol-size': '2rem' }} />;
```

### Readonly

Use the `readonly` attribute to display a rating that users can't change.

```html preview
<sl-rating readonly value="3"></sl-rating>
<sl-rating label="Rating" readonly value="3"></sl-rating>
```

```jsx react
import { SlRating } from '@shoelace-style/shoelace/dist/react';

const App = () => <SlRating readonly value={3} />;
const App = () => <SlRating label="Rating" readonly value={3} />;
```

### Disabled

Use the `disable` attribute to disable the rating.

```html preview
<sl-rating disabled value="3"></sl-rating>
<sl-rating label="Rating" disabled value="3"></sl-rating>
```

```jsx react
import { SlRating } from '@shoelace-style/shoelace/dist/react';

const App = () => <SlRating disabled value={3} />;
const App = () => <SlRating label="Rating" disabled value={3} />;
```

### Custom Icons

You can provide custom icons by passing a function to the `getSymbol` property.

```html preview
<sl-rating class="rating-hearts" style="--symbol-color-active: #ff4136;"></sl-rating>
<sl-rating label="Rating" class="rating-hearts" style="--symbol-color-active: #ff4136;"></sl-rating>

<script>
const rating = document.querySelector('.rating-hearts');
Expand All @@ -104,7 +118,11 @@ import '@shoelace-style/shoelace/dist/components/icon/icon';
import { SlRating } from '@shoelace-style/shoelace/dist/react';

const App = () => (
<SlRating getSymbol={() => '<sl-icon name="heart-fill"></sl-icon>'} style={{ '--symbol-color-active': '#ff4136' }} />
<SlRating
label="Rating"
getSymbol={() => '<sl-icon name="heart-fill"></sl-icon>'}
style={{ '--symbol-color-active': '#ff4136' }}
/>
);
```

Expand All @@ -113,7 +131,7 @@ const App = () => (
You can also use the `getSymbol` property to render different icons based on value.

```html preview
<sl-rating class="rating-emojis"></sl-rating>
<sl-rating label="Rating" class="rating-emojis"></sl-rating>

<script>
const rating = document.querySelector('.rating-emojis');
Expand All @@ -134,7 +152,7 @@ function getSymbol(value) {
return `<sl-icon name="${icons[value - 1]}"></sl-icon>`;
}

const App = () => <SlRating getSymbol={getSymbol} />;
const App = () => <SlRating label="Rating" getSymbol={getSymbol} />;
```

[component-metadata:sl-rating]
2 changes: 2 additions & 0 deletions docs/resources/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ _During the beta period, these restrictions may be relaxed in the event of a mis

- 馃毃 BREAKING: removed the `base` part from `<sl-menu>` and removed an unnecessary `<div>` that made styling more difficult
- Added read-only custom properties `--auto-size-available-width` and `--auto-size-available-height` to `<sl-popup>` to improve support for overflowing popup content
- Added `label` to `<sl-rating>` to improve accessibility for screen readers
- Fixed a bug where auto-size wasn't being applied to `<sl-dropdown>` and `<sl-select>`
- Fixed a bug in `<sl-popup>` that caused auto-size to kick in before flip
- Fixed a bug in `<sl-popup>` that prevented the `arrow-padding` attribute from working as expected
- Improved accessibility of `<sl-rating>` so keyboard nav works better and screen readers announce it properly
- Improved accessibility of `<sl-spinner>` so screen readers no longer skip over it
- Removed the default hover effect in `<sl-tree-items>` to make selections more obvious

Expand Down
9 changes: 7 additions & 2 deletions src/components/rating/rating.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export default class SlRating extends LitElement {
@state() private hoverValue = 0;
@state() private isHovering = false;

/** A label to describe the rating to assistive devices. */
@property() label = '';

/** The current rating. */
@property({ type: Number }) value = 0;

Expand Down Expand Up @@ -104,13 +107,13 @@ export default class SlRating extends LitElement {
return;
}

if ((isLtr && event.key === 'ArrowLeft') || (isRtl && event.key === 'ArrowRight')) {
if (event.key === 'ArrowDown' || (isLtr && event.key === 'ArrowLeft') || (isRtl && event.key === 'ArrowRight')) {
const decrement = event.shiftKey ? 1 : this.precision;
this.value = Math.max(0, this.value - decrement);
event.preventDefault();
}

if ((isLtr && event.key === 'ArrowRight') || (isRtl && event.key === 'ArrowLeft')) {
if (event.key === 'ArrowUp' || (isLtr && event.key === 'ArrowRight') || (isRtl && event.key === 'ArrowLeft')) {
const increment = event.shiftKey ? 1 : this.precision;
this.value = Math.min(this.max, this.value + increment);
event.preventDefault();
Expand Down Expand Up @@ -189,6 +192,8 @@ export default class SlRating extends LitElement {
'rating--disabled': this.disabled,
'rating--rtl': isRtl
})}
role="slider"
aria-label=${this.label}
aria-disabled=${this.disabled ? 'true' : 'false'}
aria-readonly=${this.readonly ? 'true' : 'false'}
aria-valuenow=${this.value}
Expand Down

0 comments on commit c94db27

Please sign in to comment.