diff --git a/docs/src/__examples__/Stepper/DEFAULT.tsx b/docs/src/__examples__/Stepper/DEFAULT.tsx index 51c9e9eca6..dcf61b5607 100644 --- a/docs/src/__examples__/Stepper/DEFAULT.tsx +++ b/docs/src/__examples__/Stepper/DEFAULT.tsx @@ -1,20 +1,22 @@ import React from "react"; -import { Heading, Stepper, Stack } from "@kiwicom/orbit-components"; +import { Heading, Stepper, Stack, OrbitProvider, defaultTheme } from "@kiwicom/orbit-components"; import { Passengers } from "@kiwicom/orbit-components/icons"; export default { Example: () => ( - - - - - Travelers - - -
- -
-
+ + + + + + Travelers + + +
+ +
+
+
), exampleKnobs: [ { diff --git a/docs/src/documentation/03-components/07-interaction/stepper/03-accessibility.mdx b/docs/src/documentation/03-components/07-interaction/stepper/03-accessibility.mdx new file mode 100644 index 0000000000..955cffe8da --- /dev/null +++ b/docs/src/documentation/03-components/07-interaction/stepper/03-accessibility.mdx @@ -0,0 +1,55 @@ +--- +title: Accessibility +redirect_from: + - /components/stepper/accessibility/ +--- + +## Accessibility + +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. + +The following props provide additional information to screen readers: + +- The `ariaLabelValue` prop allows you to specify an `aria-label` attribute for the input element (stepper value) in the Stepper (StepperStateless) component. + +- The `titleDecrement` prop allows you to specify an `aria-label` attribute for the decrement icon button in the Stepper (StepperStateless) component. + +- The `titleIncrement` prop allows you to specify an `aria-label` attribute for the increment icon button in the Stepper (StepperStateless) component. + +- 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 (StepperStateless), ensuring that screen readers announce the label correctly. + +Although these props are optional for the Stepper (StepperStateless) component itself, it is recommended to fill them in. + +### Example + +```jsx + +``` + +The screen reader will announce the value title (`Number of passengers`) and buttons title (`Add a passenger`, `Remove a passenger`) once they are focused by the screen reader. + +```jsx + + + Passengers + + + +``` + +This example includes `ariaLabelledby` prop. In this case, `ariaLabelledBy` prop is prioritized over `ariaLabelValue`, so the screen reader will announce the value title (`Passengers`) and buttons title (`Add a passenger`, `Remove a passenger`) once they are focused by the screen reader. diff --git a/packages/orbit-components/src/Stepper/README.md b/packages/orbit-components/src/Stepper/README.md index 664b196b0f..1caedf1c02 100644 --- a/packages/orbit-components/src/Stepper/README.md +++ b/packages/orbit-components/src/Stepper/README.md @@ -31,15 +31,10 @@ 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 - -| size | -| :--------- | -| `"small"` | -| `"normal"` | +| titleDecrement | `string \| (any => string)` | | Specifies `aria-label` property on decrement `Button`. | +| titleIncrement | `string \| (any => string)` | | Specifies `aria-label` property on increment `Button`. | +| ariaLabelValue | `string` | | Optional prop for `aria-label` value. | +| ariaLabelledBy | `string` | | Optional prop for `aria-labelledby` value. | ## Functional specs @@ -77,9 +72,11 @@ Table below contains all types of the props available in `StepperStateless` comp | 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`. | +| titleDecrement | `string \| (any => string)` | | Specifies `aria-label` property on decrement `Button`. | +| titleIncrement | `string \| (any => string)` | | Specifies `aria-label` property on increment `Button`. | | value | `number \| string` | | Specifies the value of the StepperStateless. | +| ariaLabelValue | `string` | | Optional prop for `aria-label` value. | +| ariaLabelledBy | `string` | | Optional prop for `aria-labelledby` value. | ### Usage: diff --git a/packages/orbit-components/src/Stepper/Stepper.stories.tsx b/packages/orbit-components/src/Stepper/Stepper.stories.tsx index 5ef658105d..429fdb0e91 100644 --- a/packages/orbit-components/src/Stepper/Stepper.stories.tsx +++ b/packages/orbit-components/src/Stepper/Stepper.stories.tsx @@ -23,12 +23,19 @@ export const Default: Story = { disable: true, }, }, + + args: { + ariaLabelValue: "Number of passengers", + titleIncrement: "Add a passenger", + titleDecrement: "Remove a passenger", + }, }; export const Playground: Story = { args: { + ...Default.args, id: "stepper-ID", - name: "Passengers number", + name: "Number of passengers", step: 1, minValue: 0, maxValue: 20, @@ -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 = { }; export const Rtl: Story = { - render: () => ( + render: args => ( - + ), @@ -95,4 +100,8 @@ export const Rtl: Story = { disable: true, }, }, + + args: { + ...Default.args, + }, }; diff --git a/packages/orbit-components/src/Stepper/StepperStateless/index.tsx b/packages/orbit-components/src/Stepper/StepperStateless/index.tsx index f2e37b7801..aa6e235fae 100644 --- a/packages/orbit-components/src/Stepper/StepperStateless/index.tsx +++ b/packages/orbit-components/src/Stepper/StepperStateless/index.tsx @@ -8,6 +8,7 @@ import Plus from "../../icons/Plus"; import ButtonPrimitive from "../../primitives/ButtonPrimitive"; import useTheme from "../../hooks/useTheme"; import type { Props } from "./types"; +import useRandomId from "../../hooks/useRandomId"; const getMaxWidth = ({ maxWidth }: { maxWidth: string | number }) => { if (typeof maxWidth === "string") return maxWidth; @@ -48,6 +49,8 @@ const StepperStateless = ({ titleDecrement, disabledIncrement, disabledDecrement, + ariaLabelValue, + ariaLabelledBy, }: Props) => { const theme = useTheme(); @@ -60,6 +63,8 @@ const StepperStateless = ({ const isPlusDisabled = disabled || disabledIncrement || (typeof value === "number" && value >= +maxValue); + const inputId = useRandomId(); + return (
); diff --git a/packages/orbit-components/src/Stepper/index.tsx b/packages/orbit-components/src/Stepper/index.tsx index 99c92858f6..19e6492f73 100644 --- a/packages/orbit-components/src/Stepper/index.tsx +++ b/packages/orbit-components/src/Stepper/index.tsx @@ -46,6 +46,8 @@ const Stepper = ({ onChange, defaultValue = 0, maxWidth = 108, ...props }: Props titleIncrement, titleDecrement, active, + ariaLabelValue, + ariaLabelledBy, } = props; return ( diff --git a/packages/orbit-components/src/Stepper/types.d.ts b/packages/orbit-components/src/Stepper/types.d.ts index be5ee55efb..dba9b00473 100644 --- a/packages/orbit-components/src/Stepper/types.d.ts +++ b/packages/orbit-components/src/Stepper/types.d.ts @@ -15,6 +15,8 @@ export interface SharedProps extends Common.Globals { readonly maxWidth?: string | number; readonly maxValue?: number; readonly minValue?: number; + readonly ariaLabelValue?: string; + readonly ariaLabelledBy?: string; // Deviation from other stepper properties readonly titleIncrement?: string; readonly titleDecrement?: string;