-
Notifications
You must be signed in to change notification settings - Fork 153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stepper accessibility fixes #4571
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
--- | ||
title: Accessibility | ||
redirect_from: | ||
- /components/stepper/accessibility/ | ||
--- | ||
|
||
## Accessibility | ||
|
||
### Stepper | ||
|
||
The Stepper component has been designed with accessibility in mind. It can be used with keyboard navigation and includes properties that enhance the experience for users of assistive technologies. | ||
|
||
Although the `ariaLabel` and `ariaLive` props are optional for the Stepper (StepperStateless) component itself, it is recommended to fill them in to ensure that the component can be perceived by assistive technologies. This ensures that the Stepper (StepperStateless) component is accessible. | ||
|
||
Also, it is highly recommended to fill the `titleDecrement` and `titleIncrement` props in to provide a description of the decrement and increment buttons for screen readers. | ||
|
||
#### Example | ||
|
||
The content of children component is text, so it is read by screen reader. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is children component? I assume you are referring to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. leftover from another |
||
|
||
```jsx | ||
<Stepper | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would maybe add more elements to this example, as it probably wouldn't be placed in isolation but with some label? (This is based on the comment I put to the review with the image example, I just wanted to post it also here in case we add all these other props.) |
||
step={1} | ||
minValue={0} | ||
minValue={10} | ||
ariaLabel="Passengers number" | ||
titleDecrement="Remove a passenger" | ||
titleIncrement="Add a passenger" | ||
ariaLive="assertive" | ||
/> | ||
``` | ||
|
||
The screen reader will announce stepper title (`Passengers number`) and buttons title (`Add a passenger`, `Remove a passenger`) once they are focused by screen reader. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it stepper title? I thought it's title of the input? From "stepper title" I would assume it's the title for the whole component, including the buttons and displayed text. Will the screen reader first announce "Passengers number" and only then "Remove a passenger" and "Add a passenger"? It won't be "Remove a passenger", then "Passengers number" and then "Add a passenger"? |
||
In case of changing the stepper value, the screen reader will announce the new value (`ariaLive` is set to `assertive` value). |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,15 +31,9 @@ Table below contains all types of the props available in Stepper component. | |
| onChange | `number => void \| Promise` | | Function for handling onClick event. | | ||
| onFocus | `event => void \| Promise` | | Function for handling onFocus event. | | ||
| step | `number` | `1` | Specifies the value of step to increment and decrement. | | ||
| titleDecrement | `string \| (any => string)` | | Specifies `title` property on decrement `Button`. | | ||
| titleIncrement | `string \| (any => string)` | | Specifies `title` property on increment `Button`. | | ||
|
||
### size | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like |
||
|
||
| size | | ||
| :--------- | | ||
| `"small"` | | ||
| `"normal"` | | ||
| titleDecrement | `string \| (any => string)` | | Specifies `ariaLabel` property on decrement `Button`. | | ||
| titleIncrement | `string \| (any => string)` | | Specifies `ariaLabel` property on increment `Button`. | | ||
| ariaLabel | `string` | | Optional prop for `aria-label` value. [See Accessibility](#accessibility). | | ||
|
||
## Functional specs | ||
|
||
|
@@ -61,25 +55,27 @@ import StepperStateless from "@kiwicom/orbit-components/lib/Stepper/StepperState | |
|
||
Table below contains all types of the props available in `StepperStateless` component. | ||
|
||
| Name | Type | Default | Description | | ||
| :---------------- | :-------------------------- | :------ | :------------------------------------------------------ | | ||
| dataTest | `string` | | Optional prop for testing purposes. | | ||
| disabled | `boolean` | `false` | If `true`, the Stepper will be disabled. | | ||
| disabledIncrement | `boolean` | | If `true`, the increment `Button` will be disabled. | | ||
| disabledDecrement | `boolean` | | If `true`, the decrement `Button` will be disabled. | | ||
| maxValue | `number` | `∞` | Specifies the maximum value for the Stepper. | | ||
| minValue | `number` | `-∞` | Specifies the minimum value for the Stepper. | | ||
| name | `string` | | The name for the Stepper. | | ||
| onBlur | `event => void \| Promise` | | Function for handling onBlur event. | | ||
| onChange | `number => void \| Promise` | | Function for handling onClick event. | | ||
| onDecrement | `event => void \| Promise` | | Function for handling decrement event.l | | ||
| onFocus | `event => void \| Promise` | | Function for handling onFocus event. | | ||
| onIncrement | `event => void \| Promise` | | Function for handling increment event. | | ||
| onKeyDown | `event => void \| Promise` | | Function for handling onKeyDown event present on input. | | ||
| step | `number` | `1` | Specifies the value of step to increment and decrement. | | ||
| titleDecrement | `string \| (any => string)` | | Specifies `title` property on decrement `Button`. | | ||
| titleIncrement | `string \| (any => string)` | | Specifies `title` property on increment `Button`. | | ||
| value | `number \| string` | | Specifies the value of the StepperStateless. | | ||
| Name | Type | Default | Description | | ||
| :---------------- | :--------------------------------- | :------ | :------------------------------------------------------------------------- | | ||
| dataTest | `string` | | Optional prop for testing purposes. | | ||
| disabled | `boolean` | `false` | If `true`, the Stepper will be disabled. | | ||
| disabledIncrement | `boolean` | | If `true`, the increment `Button` will be disabled. | | ||
| disabledDecrement | `boolean` | | If `true`, the decrement `Button` will be disabled. | | ||
| maxValue | `number` | `∞` | Specifies the maximum value for the Stepper. | | ||
| minValue | `number` | `-∞` | Specifies the minimum value for the Stepper. | | ||
| name | `string` | | The name for the Stepper. | | ||
| onBlur | `event => void \| Promise` | | Function for handling onBlur event. | | ||
| onChange | `number => void \| Promise` | | Function for handling onClick event. | | ||
| onDecrement | `event => void \| Promise` | | Function for handling decrement event. | | ||
| onFocus | `event => void \| Promise` | | Function for handling onFocus event. | | ||
| onIncrement | `event => void \| Promise` | | Function for handling increment event. | | ||
| onKeyDown | `event => void \| Promise` | | Function for handling onKeyDown event present on input. | | ||
| step | `number` | `1` | Specifies the value of step to increment and decrement. | | ||
| titleDecrement | `string \| (any => string)` | | Specifies `ariaLabel` property on decrement `Button`. | | ||
| titleIncrement | `string \| (any => string)` | | Specifies `ariaLabel` property on increment `Button`. | | ||
| value | `number \| string` | | Specifies the value of the StepperStateless. | | ||
| ariaLabel | `string` | | Optional prop for `aria-label` value. [See Accessibility](#accessibility). | | ||
| ariaLive | `"off" \| "assertive" \| "polite"` | | Optional prop for `aria-live` value. [See Accessibility](#accessibility). | | ||
|
||
### Usage: | ||
|
||
|
@@ -131,3 +127,19 @@ Helper function for validating decrement. Can be used with Stateless Stepper to | |
```js | ||
validateDecrement({ value, minValue, step }); | ||
``` | ||
|
||
## Accessibility | ||
|
||
- The `ariaLabel` prop allows you to specify an `aria-label` attribute for the Stepper input component. This attribute provides additional information to screen readers, enhancing the accessibility of the component. By using `ariaLabel`, you can ensure that users who rely on assistive technologies receive the necessary context and information about the component's purpose and functionality. | ||
|
||
- The `titleDecrement` prop allows you to specify an `aria-label` attribute for the decrement icon button in the Stepper (StepperStateless) component. This attribute helps screen readers to announce the purpose of the decrement button, making it clear that it decreases the value. | ||
|
||
- The `titleIncrement` prop allows you to specify an `aria-label` attribute for the increment icon button in the Stepper (StepperStateless) component. This attribute helps screen readers to announce the purpose of the increment button, making it clear that it increases the value. | ||
|
||
- The `ariaLive` prop allows you to specify an `aria-live` attribute for the Stepper component. This attribute is used to inform assistive technologies of updates to the content. | ||
|
||
- The `ariaDescribedBy` prop allows you to specify an `aria-describedby` attribute for the Stepper component. This attribute references the IDs of elements that describe the Stepper, providing additional context to screen readers. | ||
|
||
- The `ariaControls` prop allows you to specify an `aria-controls` attribute for the Stepper component. This attribute references the ID of the element that the Stepper controls, helping users understand the relationship between the Stepper and the controlled element. | ||
|
||
- The `ariaLabelledBy` prop allows you to specify an `aria-labelledby` attribute for the Stepper component. This attribute references the ID of the element that labels the Stepper, ensuring that screen readers announce the label correctly. | ||
Comment on lines
+130
to
+145
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this whole section is very overwhelming.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Regarding the duplication of the words, I can have it in a following form:
WDYT? |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,10 +23,17 @@ export const Default: Story = { | |
disable: true, | ||
}, | ||
}, | ||
|
||
args: { | ||
ariaLabel: "Passengers number", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe "Number of passengers" would be better name 🤔 (Same for the example in the docs) |
||
titleIncrement: "Add a passenger", | ||
titleDecrement: "Remove a passenger", | ||
}, | ||
}; | ||
|
||
export const Playground: Story = { | ||
args: { | ||
...Default.args, | ||
id: "stepper-ID", | ||
name: "Passengers number", | ||
step: 1, | ||
|
@@ -36,8 +43,6 @@ export const Playground: Story = { | |
active: false, | ||
disabled: false, | ||
maxWidth: 120, | ||
titleIncrement: "Add a passenger", | ||
titleDecrement: "Remove a passenger", | ||
onChange: action("onChange"), | ||
onFocus: action("onFocus"), | ||
onBlur: action("onBlur"), | ||
|
@@ -83,9 +88,9 @@ export const Stateless: Story & StoryObj<typeof StatelessStepper> = { | |
}; | ||
|
||
export const Rtl: Story = { | ||
render: () => ( | ||
render: args => ( | ||
<RenderInRtl> | ||
<Stepper /> | ||
<Stepper {...args} /> | ||
</RenderInRtl> | ||
), | ||
|
||
|
@@ -95,4 +100,8 @@ export const Rtl: Story = { | |
disable: true, | ||
}, | ||
}, | ||
|
||
args: { | ||
...Default.args, | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,6 +48,8 @@ const StepperStateless = ({ | |
titleDecrement, | ||
disabledIncrement, | ||
disabledDecrement, | ||
ariaLabel, | ||
ariaLive, | ||
}: Props) => { | ||
const theme = useTheme(); | ||
|
||
|
@@ -77,8 +79,8 @@ const StepperStateless = ({ | |
onDecrement(ev); | ||
} | ||
}} | ||
title={titleDecrement} | ||
icons={iconStyles} | ||
title={titleDecrement} | ||
/> | ||
<input | ||
className={cx( | ||
|
@@ -103,6 +105,8 @@ const StepperStateless = ({ | |
}} | ||
onBlur={onBlur} | ||
onFocus={onFocus} | ||
aria-label={ariaLabel} | ||
aria-live={ariaLive} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tbh, I am not sure if it's the best idea to include There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What made you add aria-live here, did you see it recommended somewhere? I was looking at documentation and found this:
If user is using Stepper component, his focus is on this component so I don't think we should be adding this here. |
||
readOnly | ||
/> | ||
<ButtonPrimitive | ||
|
@@ -115,8 +119,8 @@ const StepperStateless = ({ | |
onIncrement(ev); | ||
} | ||
}} | ||
title={titleIncrement} | ||
icons={iconStyles} | ||
title={titleIncrement} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking of changing this prop name from I'm not sure if it makes sense to change this prop name, if it could be included within this PR or in a separate one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So your suggestion is to keep prop names in Stepper as But anyway, I think it's out of scope and this should be tackled when making There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, that wouldn't make sense. :D My suggestion was to rename aria attribute in As you said, I also think it's out of the scope of this PR, that's the reason why I didn't touch ButtonPrimitive at all. |
||
/> | ||
</div> | ||
); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why didn't you add the same table as in the Seat Accessibility tab?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there's no specific reason why I added it as a section (as it's in some other components). but I agree we can have accessibility things only in accessibility tags.