Skip to content

Commit

Permalink
chore: Document how to use form controls in a Field (Set) (#1548)
Browse files Browse the repository at this point in the history
Co-authored-by: Vincent Smedinga <[email protected]>
  • Loading branch information
alimpens and VincentSmedinga authored Sep 3, 2024
1 parent 96524b0 commit cb354c9
Show file tree
Hide file tree
Showing 18 changed files with 348 additions and 55 deletions.
3 changes: 3 additions & 0 deletions documentation/storybook.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ Follow these guidelines:
unless this has side effects e.g. rendering a class name.
In that case, don’t specify a value.
Storybook will then display a button ‘Set boolean’ that show a switch.
2. Hide args with `table: { disable: true }` in the `argTypes` object if they don’t apply to the story,
e.g. if the story composes multiple instances of the component.
We don’t hide ‘less relevant’ args in other cases, not even in stories that focus on a single prop.

### Arg Types

Expand Down
4 changes: 2 additions & 2 deletions packages/css/src/components/radio/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ Allows users to select one option from a list.

## Guidelines

- Do not assume that users will know how many options they can select based on the visual difference between radios and checkboxes alone.
- Do not assume that users will know how many options they can select based on the visual difference between Radios and Checkboxes alone.
If needed, add a hint explaining this, for example, ‘Select one option’.
- Order radio options alphabetically by default.
- Order Radios alphabetically by default.
In some cases, it can be helpful to order them from most-to-least common options.
For example, you could order options for ‘Where do you live?’ based on population size.
However you should do this with extreme caution as it can reinforce bias.
Expand Down
18 changes: 18 additions & 0 deletions storybook/src/components/DateInput/DateInput.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,21 @@ Alternatives:
This helps the user understand the context.

<Canvas of={DateInputStories.Disabled} />

### In a Field

Use a Field to group a Date Input with a Label, description and / or an Error Message.

If you don’t need the description, remove its Paragraph and the `aria-describedby` from the Date Input.

Check [the Field docs](/docs/components-forms-field--docs) for more information on configuring it.

<Canvas of={DateInputStories.InAField} />

### In a Field with validation

If the Date Input can become invalid, add an Error Message and its `id` to the `aria-describedby` attribute of the Date Input.

Check [the Field docs](/docs/components-forms-field--docs) for more information on configuring it.

<Canvas of={DateInputStories.InAFieldWithValidation} />
30 changes: 30 additions & 0 deletions storybook/src/components/DateInput/DateInput.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright Gemeente Amsterdam
*/

import { ErrorMessage, Field, Label, Paragraph } from '@amsterdam/design-system-react'
import { DateInput } from '@amsterdam/design-system-react/src'
import { Meta, StoryObj } from '@storybook/react'

Expand Down Expand Up @@ -43,3 +44,32 @@ export const Disabled: Story = {
disabled: true,
},
}

export const InAField: Story = {
render: (args) => (
<Field invalid={args.invalid}>
<Label htmlFor="input1">Label</Label>
<Paragraph id="description1" size="small">
Omschrijving.
</Paragraph>
{args.invalid && <ErrorMessage id="error1">Foutmelding.</ErrorMessage>}
<DateInput aria-describedby={`description1${args.invalid ? ' error1' : ''}`} id="input1" {...args} />
</Field>
),
}

export const InAFieldWithValidation: Story = {
args: {
invalid: true,
},
render: (args) => (
<Field invalid={args.invalid}>
<Label htmlFor="input2">Label</Label>
<Paragraph id="description2" size="small">
Omschrijving.
</Paragraph>
{args.invalid && <ErrorMessage id="error2">Foutmelding.</ErrorMessage>}
<DateInput aria-describedby={`description2${args.invalid ? ' error2' : ''}`} id="input2" {...args} />
</Field>
),
}
6 changes: 3 additions & 3 deletions storybook/src/components/Field/Field.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ Add an `aria-describedby` attribute to the input and provide the `id` of the des

<Canvas of={FieldStories.WithDescription} />

## With error
## With validation

A Field can indicate if the contained input has a validation error.
Use Error Message to describe the error.
Make sure to connect the error message to the input in the Field,
Make sure to connect the Error Message to the input in the Field,
otherwise it won’t be read by a screen reader.
Add an `aria-describedby` attribute to the input and provide the `id` of Error Message as its value.

<Canvas of={FieldStories.WithError} />
<Canvas of={FieldStories.WithValidation} />
2 changes: 1 addition & 1 deletion storybook/src/components/Field/Field.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const WithDescription: Story = {
),
}

export const WithError: Story = {
export const WithValidation: Story = {
args: { invalid: true },
render: (args) => (
<Field invalid={args.invalid}>
Expand Down
31 changes: 16 additions & 15 deletions storybook/src/components/FieldSet/FieldSet.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import README from "../../../../packages/css/src/components/field-set/README.md?

## Examples

## With Description
## With description

A Field Set can have a description.
Make sure to connect this description to the Field Set or a specific input,
Expand All @@ -24,36 +24,37 @@ and provide the `id` of the describing element as its value.

<Canvas of={FieldSetStories.WithDescription} />

## With Error
## With validation

A Field Set can indicate whether any of the inputs it contains has a validation error.
Use Error Message to describe the error.
Make sure to connect the error message to the correct input in the Field Set,
Make sure to connect the Error Message to the correct input in the Field Set,
otherwise it won’t be read by a screen reader.
Add an `aria-describedby` attribute to the input and provide the `id` of Error Message as its value.

<Canvas of={FieldSetStories.WithError} />
<Canvas of={FieldSetStories.WithValidation} />

### Radio group

Use a Field Set to group radio buttons.
When grouping radio inputs, use `role="radiogroup"` on Field Set to have this grouping explicitly announced as a radio group (the default role is `group`).
Using `role="radiogroup"` also allows you to use `aria-required` on Field Set, which isn’t allowed for role `group`.
Always also set `aria-required` on the individual radio buttons though, to make sure it’s read by screen readers.
Use a Field Set to group several Radios with a legend, description, and / or an Error Message.

Add `role="radiogroup"` to the Field Set to have it explicitly announced as a radio group (the default role is just ‘group’).
The ‘radio group’ role also allows using `aria-required` on Field Set; that isn’t allowed for the ‘group’ role.
Even so, always set `aria-required` on the individual Radios as well to ensure that screen readers can read it.

<Canvas of={FieldSetStories.RadioGroup} />

### Radio group with error
### Radio group with validation

A Field Set with a radio button group can also have a validation error.
In this case, connect the error message to the Field Set instead of an input.
A Field Set with a Radio group can also have a validation error.
In this case, connect the Error Message to the Field Set instead of an input.
Add an `aria-describedby` attribute to the Field Set and provide the `id` of Error Message as its value.

<Canvas of={FieldSetStories.RadioGroupWithError} />
<Canvas of={FieldSetStories.RadioGroupWithValidation} />

### Checkbox group

Use a Field Set to group checkboxes.
Use a Field Set to group Checkboxes.

Please note: [NVDA has a bug](https://github.com/nvaccess/nvda/issues/12718) which causes it to
not report a description connected to a Field Set when it contains checkboxes.
Expand All @@ -78,7 +79,7 @@ The order of the `id`s is the order in which they are read by screen readers.

<Canvas of={FieldSetStories.CheckboxGroup} />

### Checkbox group with error
### Checkbox group with validation

Because of [the NVDA bug mentioned earlier](https://github.com/nvaccess/nvda/issues/12718),
we add the Error Message text to the label as well.
Expand All @@ -97,4 +98,4 @@ Add an `id` to the Field Set and the Error Message, and add both to the `aria-la

The order of the `id`s is the order in which they are read by screen readers.

<Canvas of={FieldSetStories.CheckboxGroupWithError} />
<Canvas of={FieldSetStories.CheckboxGroupWithValidation} />
6 changes: 3 additions & 3 deletions storybook/src/components/FieldSet/FieldSet.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const WithDescription: Story = {
),
}

export const WithError: Story = {
export const WithValidation: Story = {
args: { invalid: true },
render: (args) => (
<FieldSet invalid={args.invalid} legend={args.legend} aria-describedby="description-c">
Expand Down Expand Up @@ -162,7 +162,7 @@ export const RadioGroup: Story = {
),
}

export const RadioGroupWithError: Story = {
export const RadioGroupWithValidation: Story = {
args: {
legend: 'Waar gaat uw melding over?',
invalid: true,
Expand Down Expand Up @@ -238,7 +238,7 @@ export const CheckboxGroup: Story = {
),
}

export const CheckboxGroupWithError: Story = {
export const CheckboxGroupWithValidation: Story = {
args: {
invalid: true,
legend: 'Waar gaat uw melding over?',
Expand Down
18 changes: 15 additions & 3 deletions storybook/src/components/FileInput/FileInput.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,32 @@ import README from "../../../../packages/css/src/components/file-input/README.md

<Controls />

## Multiple Files
## Examples

### Multiple Files

Allow multiple files to be selected. The label will update to show the number of files selected.

<Canvas of={FileInputStories.Multiple} />

## Accept
### Accept

Limit the types of files that can be selected. Some examples are `image/*`, `video/*`, or `audio/*`. To limit to a specific file type, use the MIME type, such as `application/pdf`.

- [MDN File Input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#limiting_accepted_file_types): More examples

<Canvas of={FileInputStories.Accept} />

## Disabled
### Disabled

<Canvas of={FileInputStories.Disabled} />

### In a Field

Use a Field component to group a File Input with a Label and possibly a description.

If you don’t need the description, remove its Paragraph and the `aria-describedby` from the Text Input.

Check [the Field docs](/docs/components-forms-field--docs) for more information on configuring it.

<Canvas of={FileInputStories.InAField} />
13 changes: 13 additions & 0 deletions storybook/src/components/FileInput/FileInput.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright Gemeente Amsterdam
*/

import { Field, Label, Paragraph } from '@amsterdam/design-system-react'
import { FileInput } from '@amsterdam/design-system-react/src'
import { Meta, StoryObj } from '@storybook/react'

Expand Down Expand Up @@ -50,3 +51,15 @@ export const Accept: Story = {
export const Disabled: Story = {
args: { disabled: true },
}

export const InAField: Story = {
render: (args) => (
<Field>
<Label htmlFor="input1">Label</Label>
<Paragraph id="description1" size="small">
Omschrijving.
</Paragraph>
<FileInput aria-describedby="description1" id="input1" {...args} />
</Field>
),
}
22 changes: 21 additions & 1 deletion storybook/src/components/PasswordInput/PasswordInput.docs.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{/* @license CC0-1.0 */}

import { Controls, Markdown, Meta, Primary } from "@storybook/blocks";
import { Canvas, Controls, Markdown, Meta, Primary } from "@storybook/blocks";
import * as PasswordInputStories from "./PasswordInput.stories.tsx";
import README from "../../../../packages/css/src/components/password-input/README.md?raw";

Expand All @@ -11,3 +11,23 @@ import README from "../../../../packages/css/src/components/password-input/READM
<Primary />

<Controls />

## Examples

### In a Field

Use a Field to group a Password Input with a Label, description and / or an Error Message.

If you don’t need the description, remove its Paragraph and the `aria-describedby` from the Password Input.

Check [the Field docs](/docs/components-forms-field--docs) for more information on configuring it.

<Canvas of={PasswordInputStories.InAField} />

### In a Field with validation

If the Password Input can become invalid, add an Error Message and its `id` to the `aria-describedby` attribute of the Password Input.

Check [the Field docs](/docs/components-forms-field--docs) for more information on configuring it.

<Canvas of={PasswordInputStories.InAFieldWithValidation} />
30 changes: 30 additions & 0 deletions storybook/src/components/PasswordInput/PasswordInput.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright Gemeente Amsterdam
*/

import { ErrorMessage, Field, Label, Paragraph } from '@amsterdam/design-system-react'
import { PasswordInput } from '@amsterdam/design-system-react/src'
import { Meta, StoryObj } from '@storybook/react'

Expand All @@ -25,3 +26,32 @@ export default meta
type Story = StoryObj<typeof meta>

export const Default: Story = {}

export const InAField: Story = {
render: (args) => (
<Field invalid={args.invalid}>
<Label htmlFor="input1">Label</Label>
<Paragraph id="description1" size="small">
Omschrijving.
</Paragraph>
{args.invalid && <ErrorMessage id="error1">Foutmelding.</ErrorMessage>}
<PasswordInput aria-describedby={`description1${args.invalid ? ' error1' : ''}`} id="input1" {...args} />
</Field>
),
}

export const InAFieldWithValidation: Story = {
args: {
invalid: true,
},
render: (args) => (
<Field invalid={args.invalid}>
<Label htmlFor="input2">Label</Label>
<Paragraph id="description2" size="small">
Omschrijving.
</Paragraph>
{args.invalid && <ErrorMessage id="error2">Foutmelding.</ErrorMessage>}
<PasswordInput aria-describedby={`description2${args.invalid ? ' error2' : ''}`} id="input2" {...args} />
</Field>
),
}
25 changes: 22 additions & 3 deletions storybook/src/components/Radio/Radio.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,26 @@ import README from "../../../../packages/css/src/components/radio/README.md?raw"

<Controls />

Group radios together with a [Field Set](/docs/components-forms-field-set--docs) that describes them.
This is usually a question, like ‘Where do you live?’.
## Examples

<Canvas of={RadioStories.RadioGroup} />
### In a Field Set

Use a Field Set to group several Radios with a legend, description and / or an error message.

Add `role="radiogroup"` to the Field Set to have it explicitly announced as a radio group (the default role is just ‘group’).
The ‘radio group’ role also allows using `aria-required` on Field Set; that isn’t allowed for the ‘group’ role.
Even so, always set `aria-required` on the individual Radios as well to ensure that screen readers can read it.

If you don’t need the description, remove its Paragraph and the `aria-describedby` from the Field Set.

Check [the Field Set docs](/docs/components-forms-field-set--docs) for more information on configuring it.

<Canvas of={RadioStories.InAFieldSet} />

### In a Field Set With Validation

If the Radio can become invalid, add an Error Message component and its `id` to the `aria-describedby` attribute of the Field Set.

Check [the Field Set docs](/docs/components-forms-field-set--docs) for more information on configuring it.

<Canvas of={RadioStories.InAFieldSetWithValidation} />
Loading

0 comments on commit cb354c9

Please sign in to comment.