From a6eedd8f1995a5660f650c79ab9e0805c8b271b2 Mon Sep 17 00:00:00 2001 From: Aram Limpens Date: Fri, 31 May 2024 15:41:10 +0200 Subject: [PATCH 01/13] Add ErrorMessage component --- .../src/components/error-message/README.md | 3 ++ .../error-message/error-message.scss | 22 +++++++++++ packages/css/src/components/index.scss | 1 + .../src/ErrorMessage/ErrorMessage.test.tsx | 37 +++++++++++++++++++ .../react/src/ErrorMessage/ErrorMessage.tsx | 20 ++++++++++ packages/react/src/ErrorMessage/README.md | 5 +++ packages/react/src/ErrorMessage/index.ts | 2 + packages/react/src/index.ts | 1 + .../components/ams/error-message.tokens.json | 11 ++++++ .../ErrorMessage/ErrorMessage.docs.mdx | 11 ++++++ .../ErrorMessage/ErrorMessage.stories.tsx | 21 +++++++++++ 11 files changed, 134 insertions(+) create mode 100644 packages/css/src/components/error-message/README.md create mode 100644 packages/css/src/components/error-message/error-message.scss create mode 100644 packages/react/src/ErrorMessage/ErrorMessage.test.tsx create mode 100644 packages/react/src/ErrorMessage/ErrorMessage.tsx create mode 100644 packages/react/src/ErrorMessage/README.md create mode 100644 packages/react/src/ErrorMessage/index.ts create mode 100644 proprietary/tokens/src/components/ams/error-message.tokens.json create mode 100644 storybook/src/components/ErrorMessage/ErrorMessage.docs.mdx create mode 100644 storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx diff --git a/packages/css/src/components/error-message/README.md b/packages/css/src/components/error-message/README.md new file mode 100644 index 0000000000..c64fb659cf --- /dev/null +++ b/packages/css/src/components/error-message/README.md @@ -0,0 +1,3 @@ + + +# Error Message diff --git a/packages/css/src/components/error-message/error-message.scss b/packages/css/src/components/error-message/error-message.scss new file mode 100644 index 0000000000..4dd6e3fd19 --- /dev/null +++ b/packages/css/src/components/error-message/error-message.scss @@ -0,0 +1,22 @@ +/** + * @license EUPL-1.2+ + * Copyright Gemeente Amsterdam + */ + +@import "../../common/text-rendering"; + +@mixin reset { + box-sizing: border-box; + margin-block: 0; +} + +.ams-error-message { + color: var(--ams-error-message-color); + font-family: var(--ams-error-message-font-family); + font-size: var(--ams-error-message-font-size); + font-weight: var(--ams-error-message-font-weight); + line-height: var(--ams-error-message-line-height); + + @include text-rendering; + @include reset; +} diff --git a/packages/css/src/components/index.scss b/packages/css/src/components/index.scss index 5f7cf2d09a..92badfec90 100644 --- a/packages/css/src/components/index.scss +++ b/packages/css/src/components/index.scss @@ -4,6 +4,7 @@ */ /* Append here */ +@import "./error-message/error-message"; @import "./file-input/file-input"; @import "./field/field"; @import "./select/select"; diff --git a/packages/react/src/ErrorMessage/ErrorMessage.test.tsx b/packages/react/src/ErrorMessage/ErrorMessage.test.tsx new file mode 100644 index 0000000000..dbe17b9c39 --- /dev/null +++ b/packages/react/src/ErrorMessage/ErrorMessage.test.tsx @@ -0,0 +1,37 @@ +import { render, screen } from '@testing-library/react' +import { createRef } from 'react' +import { ErrorMessage } from './ErrorMessage' +import '@testing-library/jest-dom' + +describe('Error message', () => { + it('renders', () => { + render() + const component = screen.getByRole('paragraph') + + expect(component).toBeInTheDocument() + expect(component).toBeVisible() + }) + + it('renders a design system BEM class name', () => { + render() + const component = screen.getByRole('paragraph') + + expect(component).toHaveClass('ams-error-message') + }) + + it('renders an additional class name', () => { + render() + const component = screen.getByRole('paragraph') + + expect(component).toHaveClass('ams-error-message extra') + }) + + it('supports ForwardRef in React', () => { + const ref = createRef() + + render() + const component = screen.getByRole('paragraph') + + expect(ref.current).toBe(component) + }) +}) diff --git a/packages/react/src/ErrorMessage/ErrorMessage.tsx b/packages/react/src/ErrorMessage/ErrorMessage.tsx new file mode 100644 index 0000000000..a696830812 --- /dev/null +++ b/packages/react/src/ErrorMessage/ErrorMessage.tsx @@ -0,0 +1,20 @@ +/** + * @license EUPL-1.2+ + * Copyright Gemeente Amsterdam + */ + +import clsx from 'clsx' +import { forwardRef } from 'react' +import type { ForwardedRef, HTMLAttributes, PropsWithChildren } from 'react' + +export type ErrorMessageProps = PropsWithChildren> + +export const ErrorMessage = forwardRef( + ({ children, className, ...restProps }: ErrorMessageProps, ref: ForwardedRef) => ( +

+ {children} +

+ ), +) + +ErrorMessage.displayName = 'ErrorMessage' diff --git a/packages/react/src/ErrorMessage/README.md b/packages/react/src/ErrorMessage/README.md new file mode 100644 index 0000000000..b7a1e98d1a --- /dev/null +++ b/packages/react/src/ErrorMessage/README.md @@ -0,0 +1,5 @@ + + +# React Error Message component + +[Error Message documentation](../../../css/src/components/error-message/README.md) diff --git a/packages/react/src/ErrorMessage/index.ts b/packages/react/src/ErrorMessage/index.ts new file mode 100644 index 0000000000..50e3b5c5c3 --- /dev/null +++ b/packages/react/src/ErrorMessage/index.ts @@ -0,0 +1,2 @@ +export { ErrorMessage } from './ErrorMessage' +export type { ErrorMessageProps } from './ErrorMessage' diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 4334528431..c7bd65c925 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -4,6 +4,7 @@ */ /* Append here */ +export * from './ErrorMessage' export * from './FileInput' export * from './Field' export * from './Select' diff --git a/proprietary/tokens/src/components/ams/error-message.tokens.json b/proprietary/tokens/src/components/ams/error-message.tokens.json new file mode 100644 index 0000000000..a742de7279 --- /dev/null +++ b/proprietary/tokens/src/components/ams/error-message.tokens.json @@ -0,0 +1,11 @@ +{ + "ams": { + "error-message": { + "color": { "value": "{ams.color.primary-red}" }, + "font-family": { "value": "{ams.text.font-family}" }, + "font-size": { "value": "{ams.text.level.6.font-size}" }, + "font-weight": { "value": "{ams.text.font-weight.normal}" }, + "line-height": { "value": "{ams.text.level.6.line-height}" } + } + } +} diff --git a/storybook/src/components/ErrorMessage/ErrorMessage.docs.mdx b/storybook/src/components/ErrorMessage/ErrorMessage.docs.mdx new file mode 100644 index 0000000000..0220f7416a --- /dev/null +++ b/storybook/src/components/ErrorMessage/ErrorMessage.docs.mdx @@ -0,0 +1,11 @@ +import { Controls, Markdown, Meta, Primary } from "@storybook/blocks"; +import * as ErrorMessageStories from "./ErrorMessage.stories.tsx"; +import README from "../../../../packages/css/src/components/error-message/README.md?raw"; + + + +{README} + + + + diff --git a/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx b/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx new file mode 100644 index 0000000000..2b9a867ac3 --- /dev/null +++ b/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx @@ -0,0 +1,21 @@ +/** + * @license EUPL-1.2+ + * Copyright Gemeente Amsterdam + */ + +import { ErrorMessage } from '@amsterdam/design-system-react/src' +import { Meta, StoryObj } from '@storybook/react' + +const meta = { + title: 'Error Message', + component: ErrorMessage, + args: { + children: 'Nieuw component', + }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +export const Default: Story = {} From 08d99562778deef6f7d9d501f5625c5e6fd20e96 Mon Sep 17 00:00:00 2001 From: Aram Limpens Date: Fri, 31 May 2024 16:10:00 +0200 Subject: [PATCH 02/13] Add ErrorMessage to Field docs --- packages/react/src/Field/Field.tsx | 10 ++++++++-- packages/react/src/FieldSet/FieldSet.tsx | 7 +++++-- .../components/ErrorMessage/ErrorMessage.stories.tsx | 7 ++++++- storybook/src/components/Field/Field.docs.mdx | 6 +++++- storybook/src/components/Field/Field.stories.tsx | 11 ++++++----- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/packages/react/src/Field/Field.tsx b/packages/react/src/Field/Field.tsx index e8404fbf10..094374a61e 100644 --- a/packages/react/src/Field/Field.tsx +++ b/packages/react/src/Field/Field.tsx @@ -6,13 +6,15 @@ import clsx from 'clsx' import { forwardRef } from 'react' import type { ForwardedRef, HTMLAttributes, PropsWithChildren } from 'react' +import { ErrorMessage } from '../ErrorMessage' +import { Label } from '../Label' export type FieldProps = { /** Whether the field has an input with a validation error */ invalid?: boolean } & PropsWithChildren> -export const Field = forwardRef( +const FieldRoot = forwardRef( ({ children, className, invalid, ...restProps }: FieldProps, ref: ForwardedRef) => (
{children} @@ -20,4 +22,8 @@ export const Field = forwardRef( ), ) -Field.displayName = 'Field' +FieldRoot.displayName = 'Field' +ErrorMessage.displayName = 'Field.ErrorMessage' +Label.displayName = 'Field.Label' + +export const Field = Object.assign(FieldRoot, { ErrorMessage: ErrorMessage, Label: Label }) diff --git a/packages/react/src/FieldSet/FieldSet.tsx b/packages/react/src/FieldSet/FieldSet.tsx index cb424ad202..fb6505fdc2 100644 --- a/packages/react/src/FieldSet/FieldSet.tsx +++ b/packages/react/src/FieldSet/FieldSet.tsx @@ -6,6 +6,7 @@ import clsx from 'clsx' import { forwardRef } from 'react' import type { ForwardedRef, HTMLAttributes, PropsWithChildren } from 'react' +import { ErrorMessage } from '../ErrorMessage' export type FieldSetProps = PropsWithChildren> & { /** Whether the field set has an input with a validation error */ @@ -14,7 +15,7 @@ export type FieldSetProps = PropsWithChildren) => (
diff --git a/storybook/src/components/Field/Field.docs.mdx b/storybook/src/components/Field/Field.docs.mdx index c2283e9caf..4510b394f7 100644 --- a/storybook/src/components/Field/Field.docs.mdx +++ b/storybook/src/components/Field/Field.docs.mdx @@ -14,7 +14,7 @@ import README from "../../../../packages/css/src/components/field/README.md?raw" A Field can have a description. Make sure to connect this description to the input in the Field, -otherwise this won’t be read by a screen reader. +otherwise it won’t be read by a screen reader. Add an `aria-describedby` attribute to the input and provide the `id` of the describing element as its value. @@ -22,5 +22,9 @@ Add an `aria-describedby` attribute to the input and provide the `id` of the des ## With Error A Field can indicate if the contained input has a validation error. +Use `Field.ErrorMessage` to describe the error. +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 `Field.ErrorMessage` as its value. diff --git a/storybook/src/components/Field/Field.stories.tsx b/storybook/src/components/Field/Field.stories.tsx index c1559c47a3..551147cc6f 100644 --- a/storybook/src/components/Field/Field.stories.tsx +++ b/storybook/src/components/Field/Field.stories.tsx @@ -4,7 +4,7 @@ */ import { TextInput } from '@amsterdam/design-system-react' -import { Field, Label, Paragraph } from '@amsterdam/design-system-react/src' +import { Field, Paragraph } from '@amsterdam/design-system-react/src' import { Meta, StoryObj } from '@storybook/react' const meta = { @@ -22,7 +22,7 @@ type Story = StoryObj export const Default: Story = { render: (args) => ( - + Waar gaat het om? ), @@ -31,7 +31,7 @@ export const Default: Story = { export const WithDescription: Story = { render: (args) => ( - + Waar gaat het om? Typ geen persoonsgegevens in deze omschrijving. We vragen dit later in dit formulier aan u. @@ -44,11 +44,12 @@ export const WithError: Story = { args: { invalid: true }, render: (args) => ( - + Waar gaat het om? Typ geen persoonsgegevens in deze omschrijving. We vragen dit later in dit formulier aan u. - + Geef aan waar het om gaat. + ), } From 270e2c943de3c0d9b7d1a8c9633360aa389927d7 Mon Sep 17 00:00:00 2001 From: Aram Limpens Date: Fri, 31 May 2024 16:54:49 +0200 Subject: [PATCH 03/13] Add FieldSet ErrorMessage docs --- .../src/components/FieldSet/FieldSet.docs.mdx | 25 +++++- .../components/FieldSet/FieldSet.stories.tsx | 81 ++++++++++++++++++- 2 files changed, 103 insertions(+), 3 deletions(-) diff --git a/storybook/src/components/FieldSet/FieldSet.docs.mdx b/storybook/src/components/FieldSet/FieldSet.docs.mdx index 4214143dec..48c8198674 100644 --- a/storybook/src/components/FieldSet/FieldSet.docs.mdx +++ b/storybook/src/components/FieldSet/FieldSet.docs.mdx @@ -25,6 +25,10 @@ and provide the `id` of the describing element as its value. ## With Error A Field Set can indicate whether any of the inputs it contains has a validation error. +Use `FieldSet.ErrorMessage` to describe the error. +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 `FieldSet.ErrorMessage` as its value. @@ -32,12 +36,19 @@ A Field Set can indicate whether any of the inputs it contains has a validation 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. +### Radio group with error + +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. +Add an `aria-describedby` attribute to the Field Set and provide the `id` of `FieldSet.ErrorMessage` as its value. + + + ### Checkbox group Use a Field Set to group checkboxes. @@ -48,3 +59,15 @@ not report a description connected to a Field Set when it contains checkboxes. Try to avoid using descriptions for Field Sets containing checkboxes for this reason. + +### Checkbox group with error + +A Field Set with a checkbox group can also have a validation error. +Because of [the NVDA bug mentioned earlier](https://github.com/nvaccess/nvda/issues/12718), we need to connect the error message to the Field Set in two ways: + +1. Add an `aria-describedby` attribute to the Field Set and provide the `id` of `FieldSet.ErrorMessage` as its value. +2. Add an `aria-errormessage` attribute to the Field Set and provide the `id` of `FieldSet.ErrorMessage` as its value. + +{/* TODO: dit werkt niet, uitvogelen */} + + diff --git a/storybook/src/components/FieldSet/FieldSet.stories.tsx b/storybook/src/components/FieldSet/FieldSet.stories.tsx index 501d5c56bd..73d2feb618 100644 --- a/storybook/src/components/FieldSet/FieldSet.stories.tsx +++ b/storybook/src/components/FieldSet/FieldSet.stories.tsx @@ -64,9 +64,11 @@ export const WithError: Story = { - + {args.invalid && Vul uw voornaam in.} + - + {args.invalid && Vul uw achternaam in.} +
), @@ -105,6 +107,45 @@ export const RadioGroup: Story = { ), } +export const RadioGroupWithError: Story = { + args: { + legend: 'Waar gaat uw melding over?', + invalid: true, + }, + render: (args) => ( +
+ + De laatstgenoemde melding. + + {args.invalid && ( + + Geef aan waar uw laatstgenoemde melding over gaat. + + )} + + + Horecabedrijf + + + Ander soort bedrijf + + + Evenement + + + Iets anders + + +
+ ), +} + export const CheckboxGroup: Story = { args: { legend: 'Waar gaat uw melding over?', @@ -128,3 +169,39 @@ export const CheckboxGroup: Story = { ), } + +export const CheckboxGroupWithError: Story = { + args: { + invalid: true, + legend: 'Waar gaat uw melding over?', + }, + render: (args) => ( +
+ {args.invalid && ( + + Geef aan waar uw melding over gaat. + + )} + + + Horecabedrijf + + + Ander soort bedrijf + + + Evenement + + + Iets anders + + +
+ ), +} From 1d7b36bdaf92603c520f026cd8ec8a491b2cc03d Mon Sep 17 00:00:00 2001 From: Aram Limpens Date: Fri, 31 May 2024 17:11:00 +0200 Subject: [PATCH 04/13] Add docs --- packages/css/src/components/error-message/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/css/src/components/error-message/README.md b/packages/css/src/components/error-message/README.md index c64fb659cf..39e61e3765 100644 --- a/packages/css/src/components/error-message/README.md +++ b/packages/css/src/components/error-message/README.md @@ -1,3 +1,10 @@ # Error Message + +Show an error message when there is a form field validation error. +In the error message explain what went wrong and how to fix it. + +See the [Field](/docs/components-forms-field--docs) and [Field Set](/docs/components-forms-field-set--docs) documentation for an explanation and examples of how to use error messages in a form. + +Read the documentation by [NL Design System](https://www.nldesignsystem.nl/richtlijnen/formulieren/foutmeldingen) and [Gov.uk](https://design-system.service.gov.uk/components/error-message/) for more information on the contents of error messages and when to show them. From 78ca5c3749801e35f936b7d567c1e453713b0731 Mon Sep 17 00:00:00 2001 From: Aram Limpens Date: Fri, 31 May 2024 17:29:39 +0200 Subject: [PATCH 05/13] Add prefix story --- packages/react/src/ErrorMessage/ErrorMessage.tsx | 11 +++++++++-- packages/react/src/Field/Field.tsx | 5 +++-- packages/react/src/FieldSet/FieldSet.tsx | 2 ++ .../src/components/ErrorMessage/ErrorMessage.docs.mdx | 10 +++++++++- .../components/ErrorMessage/ErrorMessage.stories.tsx | 7 +++++++ 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/react/src/ErrorMessage/ErrorMessage.tsx b/packages/react/src/ErrorMessage/ErrorMessage.tsx index a696830812..06cadb51af 100644 --- a/packages/react/src/ErrorMessage/ErrorMessage.tsx +++ b/packages/react/src/ErrorMessage/ErrorMessage.tsx @@ -6,12 +6,19 @@ import clsx from 'clsx' import { forwardRef } from 'react' import type { ForwardedRef, HTMLAttributes, PropsWithChildren } from 'react' +import { VisuallyHidden } from '../VisuallyHidden' -export type ErrorMessageProps = PropsWithChildren> +export type ErrorMessageProps = { + prefix?: string +} & PropsWithChildren> export const ErrorMessage = forwardRef( - ({ children, className, ...restProps }: ErrorMessageProps, ref: ForwardedRef) => ( + ( + { children, className, prefix = 'Invoerfout: ', ...restProps }: ErrorMessageProps, + ref: ForwardedRef, + ) => (

+ {prefix} {children}

), diff --git a/packages/react/src/Field/Field.tsx b/packages/react/src/Field/Field.tsx index 094374a61e..d031f05a76 100644 --- a/packages/react/src/Field/Field.tsx +++ b/packages/react/src/Field/Field.tsx @@ -23,7 +23,8 @@ const FieldRoot = forwardRef( ) FieldRoot.displayName = 'Field' -ErrorMessage.displayName = 'Field.ErrorMessage' -Label.displayName = 'Field.Label' export const Field = Object.assign(FieldRoot, { ErrorMessage: ErrorMessage, Label: Label }) + +Field.ErrorMessage.displayName = 'Field.ErrorMessage' +Field.Label.displayName = 'Field.Label' diff --git a/packages/react/src/FieldSet/FieldSet.tsx b/packages/react/src/FieldSet/FieldSet.tsx index fb6505fdc2..463dfece0f 100644 --- a/packages/react/src/FieldSet/FieldSet.tsx +++ b/packages/react/src/FieldSet/FieldSet.tsx @@ -31,3 +31,5 @@ export const FieldSetRoot = forwardRef( FieldSetRoot.displayName = 'FieldSet' export const FieldSet = Object.assign(FieldSetRoot, { ErrorMessage: ErrorMessage }) + +FieldSet.ErrorMessage.displayName = 'FieldSet.ErrorMessage' diff --git a/storybook/src/components/ErrorMessage/ErrorMessage.docs.mdx b/storybook/src/components/ErrorMessage/ErrorMessage.docs.mdx index 0220f7416a..6f5992b9c9 100644 --- a/storybook/src/components/ErrorMessage/ErrorMessage.docs.mdx +++ b/storybook/src/components/ErrorMessage/ErrorMessage.docs.mdx @@ -1,4 +1,4 @@ -import { Controls, Markdown, Meta, Primary } from "@storybook/blocks"; +import { Canvas, Controls, Markdown, Meta, Primary } from "@storybook/blocks"; import * as ErrorMessageStories from "./ErrorMessage.stories.tsx"; import README from "../../../../packages/css/src/components/error-message/README.md?raw"; @@ -9,3 +9,11 @@ import README from "../../../../packages/css/src/components/error-message/README + +## With a custom prefix + +Error messages are automatically prefixed with a visually hidden text, the Dutch phrase "Invoerfout: ". +This makes the error message more clear for screen reader users. +If you want to change this prefix, to support another language for example, you can use the `prefix` prop. + + diff --git a/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx b/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx index 400da02cf9..da269755f6 100644 --- a/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx +++ b/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx @@ -24,3 +24,10 @@ export default meta type Story = StoryObj export const Default: Story = {} + +export const WithCustomPrefix: Story = { + args: { + children: 'Enter an email address in the correct format, like name@example.com', + prefix: 'Error: ', + }, +} From 0cb940cb3c3ddb91613a2739a0c51cc95ee6e9ef Mon Sep 17 00:00:00 2001 From: Aram Limpens Date: Fri, 31 May 2024 17:37:32 +0200 Subject: [PATCH 06/13] Remove subcomponents for now --- packages/react/src/Field/Field.tsx | 11 ++----- packages/react/src/FieldSet/FieldSet.tsx | 9 ++---- .../src/components/Field/Field.stories.tsx | 10 +++--- .../components/FieldSet/FieldSet.stories.tsx | 31 ++++++++++--------- 4 files changed, 26 insertions(+), 35 deletions(-) diff --git a/packages/react/src/Field/Field.tsx b/packages/react/src/Field/Field.tsx index d031f05a76..e8404fbf10 100644 --- a/packages/react/src/Field/Field.tsx +++ b/packages/react/src/Field/Field.tsx @@ -6,15 +6,13 @@ import clsx from 'clsx' import { forwardRef } from 'react' import type { ForwardedRef, HTMLAttributes, PropsWithChildren } from 'react' -import { ErrorMessage } from '../ErrorMessage' -import { Label } from '../Label' export type FieldProps = { /** Whether the field has an input with a validation error */ invalid?: boolean } & PropsWithChildren> -const FieldRoot = forwardRef( +export const Field = forwardRef( ({ children, className, invalid, ...restProps }: FieldProps, ref: ForwardedRef) => (
{children} @@ -22,9 +20,4 @@ const FieldRoot = forwardRef( ), ) -FieldRoot.displayName = 'Field' - -export const Field = Object.assign(FieldRoot, { ErrorMessage: ErrorMessage, Label: Label }) - -Field.ErrorMessage.displayName = 'Field.ErrorMessage' -Field.Label.displayName = 'Field.Label' +Field.displayName = 'Field' diff --git a/packages/react/src/FieldSet/FieldSet.tsx b/packages/react/src/FieldSet/FieldSet.tsx index 463dfece0f..cb424ad202 100644 --- a/packages/react/src/FieldSet/FieldSet.tsx +++ b/packages/react/src/FieldSet/FieldSet.tsx @@ -6,7 +6,6 @@ import clsx from 'clsx' import { forwardRef } from 'react' import type { ForwardedRef, HTMLAttributes, PropsWithChildren } from 'react' -import { ErrorMessage } from '../ErrorMessage' export type FieldSetProps = PropsWithChildren> & { /** Whether the field set has an input with a validation error */ @@ -15,7 +14,7 @@ export type FieldSetProps = PropsWithChildren) => (
export const Default: Story = { render: (args) => ( - Waar gaat het om? + ), @@ -31,7 +31,7 @@ export const Default: Story = { export const WithDescription: Story = { render: (args) => ( - Waar gaat het om? + Typ geen persoonsgegevens in deze omschrijving. We vragen dit later in dit formulier aan u. @@ -44,11 +44,11 @@ export const WithError: Story = { args: { invalid: true }, render: (args) => ( - Waar gaat het om? + Typ geen persoonsgegevens in deze omschrijving. We vragen dit later in dit formulier aan u. - Geef aan waar het om gaat. + Geef aan waar het om gaat. ), diff --git a/storybook/src/components/FieldSet/FieldSet.stories.tsx b/storybook/src/components/FieldSet/FieldSet.stories.tsx index 73d2feb618..9f984f067d 100644 --- a/storybook/src/components/FieldSet/FieldSet.stories.tsx +++ b/storybook/src/components/FieldSet/FieldSet.stories.tsx @@ -3,7 +3,16 @@ * Copyright Gemeente Amsterdam */ -import { Checkbox, Column, FieldSet, Label, Paragraph, Radio, TextInput } from '@amsterdam/design-system-react/src' +import { + Checkbox, + Column, + ErrorMessage, + FieldSet, + Label, + Paragraph, + Radio, + TextInput, +} from '@amsterdam/design-system-react/src' import { Meta, StoryObj } from '@storybook/react' const meta = { @@ -64,10 +73,10 @@ export const WithError: Story = { - {args.invalid && Vul uw voornaam in.} + {args.invalid && Vul uw voornaam in.} - {args.invalid && Vul uw achternaam in.} + {args.invalid && Vul uw achternaam in.}
@@ -124,9 +133,9 @@ export const RadioGroupWithError: Story = { De laatstgenoemde melding. {args.invalid && ( - + Geef aan waar uw laatstgenoemde melding over gaat. - + )} @@ -176,17 +185,11 @@ export const CheckboxGroupWithError: Story = { legend: 'Waar gaat uw melding over?', }, render: (args) => ( -
+
{args.invalid && ( - + Geef aan waar uw melding over gaat. - + )} From 712753c890a1a1c5fc117371f1303c26becc12a5 Mon Sep 17 00:00:00 2001 From: Aram Limpens Date: Fri, 31 May 2024 17:46:36 +0200 Subject: [PATCH 07/13] Remove subcomponents from docs --- storybook/src/components/Field/Field.docs.mdx | 4 ++-- storybook/src/components/FieldSet/FieldSet.docs.mdx | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/storybook/src/components/Field/Field.docs.mdx b/storybook/src/components/Field/Field.docs.mdx index 4510b394f7..4a0eb86187 100644 --- a/storybook/src/components/Field/Field.docs.mdx +++ b/storybook/src/components/Field/Field.docs.mdx @@ -22,9 +22,9 @@ Add an `aria-describedby` attribute to the input and provide the `id` of the des ## With Error A Field can indicate if the contained input has a validation error. -Use `Field.ErrorMessage` to describe the error. +Use Error Message to describe the error. 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 `Field.ErrorMessage` as its value. +Add an `aria-describedby` attribute to the input and provide the `id` of Error Message as its value. diff --git a/storybook/src/components/FieldSet/FieldSet.docs.mdx b/storybook/src/components/FieldSet/FieldSet.docs.mdx index 48c8198674..38525b1750 100644 --- a/storybook/src/components/FieldSet/FieldSet.docs.mdx +++ b/storybook/src/components/FieldSet/FieldSet.docs.mdx @@ -25,10 +25,10 @@ and provide the `id` of the describing element as its value. ## With Error A Field Set can indicate whether any of the inputs it contains has a validation error. -Use `FieldSet.ErrorMessage` to describe the error. +Use Error Message to describe the error. 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 `FieldSet.ErrorMessage` as its value. +Add an `aria-describedby` attribute to the input and provide the `id` of Error Message as its value. @@ -45,7 +45,7 @@ Always also set `aria-required` on the individual radio buttons though, to make 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. -Add an `aria-describedby` attribute to the Field Set and provide the `id` of `FieldSet.ErrorMessage` as its value. +Add an `aria-describedby` attribute to the Field Set and provide the `id` of Error Message as its value. @@ -65,8 +65,8 @@ Try to avoid using descriptions for Field Sets containing checkboxes for this re A Field Set with a checkbox group can also have a validation error. Because of [the NVDA bug mentioned earlier](https://github.com/nvaccess/nvda/issues/12718), we need to connect the error message to the Field Set in two ways: -1. Add an `aria-describedby` attribute to the Field Set and provide the `id` of `FieldSet.ErrorMessage` as its value. -2. Add an `aria-errormessage` attribute to the Field Set and provide the `id` of `FieldSet.ErrorMessage` as its value. +1. Add an `aria-describedby` attribute to the Field Set and provide the `id` of Error Message as its value. +2. Add an `aria-errormessage` attribute to the Field Set and provide the `id` of Error Message as its value. {/* TODO: dit werkt niet, uitvogelen */} From b4196c224de569c18235aa36fa0fe1f244e8e9f8 Mon Sep 17 00:00:00 2001 From: Aram Limpens Date: Fri, 31 May 2024 17:48:37 +0200 Subject: [PATCH 08/13] Add component to correct folder --- storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx b/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx index da269755f6..86095bff6a 100644 --- a/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx +++ b/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx @@ -7,7 +7,7 @@ import { ErrorMessage } from '@amsterdam/design-system-react/src' import { Meta, StoryObj } from '@storybook/react' const meta = { - title: 'Error Message', + title: 'Components/Forms/Error Message', component: ErrorMessage, args: { children: 'Vul een geldig e-mailadres in, bijvoorbeeld naam@voorbeeld.nl.', From 536ecd61f4d405d8c4842e332fd2b25f08ee8a36 Mon Sep 17 00:00:00 2001 From: Aram Limpens Date: Mon, 3 Jun 2024 15:54:56 +0200 Subject: [PATCH 09/13] Remove checkbox group with error from stories --- .../src/components/FieldSet/FieldSet.docs.mdx | 14 ++--- .../components/FieldSet/FieldSet.stories.tsx | 54 +++++++++---------- 2 files changed, 29 insertions(+), 39 deletions(-) diff --git a/storybook/src/components/FieldSet/FieldSet.docs.mdx b/storybook/src/components/FieldSet/FieldSet.docs.mdx index 38525b1750..506cab411d 100644 --- a/storybook/src/components/FieldSet/FieldSet.docs.mdx +++ b/storybook/src/components/FieldSet/FieldSet.docs.mdx @@ -26,7 +26,7 @@ and provide the `id` of the describing element as its value. 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 input in the Field, +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. @@ -62,12 +62,6 @@ Try to avoid using descriptions for Field Sets containing checkboxes for this re ### Checkbox group with error -A Field Set with a checkbox group can also have a validation error. -Because of [the NVDA bug mentioned earlier](https://github.com/nvaccess/nvda/issues/12718), we need to connect the error message to the Field Set in two ways: - -1. Add an `aria-describedby` attribute to the Field Set and provide the `id` of Error Message as its value. -2. Add an `aria-errormessage` attribute to the Field Set and provide the `id` of Error Message as its value. - -{/* TODO: dit werkt niet, uitvogelen */} - - +Because of [the NVDA bug mentioned earlier](https://github.com/nvaccess/nvda/issues/12718), +we currently do not have a reliable way to report error messages for checkbox groups with a validation error. +We are working on adding this as soon as possible. diff --git a/storybook/src/components/FieldSet/FieldSet.stories.tsx b/storybook/src/components/FieldSet/FieldSet.stories.tsx index 9f984f067d..1aed9b47b9 100644 --- a/storybook/src/components/FieldSet/FieldSet.stories.tsx +++ b/storybook/src/components/FieldSet/FieldSet.stories.tsx @@ -179,32 +179,28 @@ export const CheckboxGroup: Story = { ), } -export const CheckboxGroupWithError: Story = { - args: { - invalid: true, - legend: 'Waar gaat uw melding over?', - }, - render: (args) => ( -
- {args.invalid && ( - - Geef aan waar uw melding over gaat. - - )} - - - Horecabedrijf - - - Ander soort bedrijf - - - Evenement - - - Iets anders - - -
- ), -} +// export const CheckboxGroupWithError: Story = { +// args: { +// invalid: true, +// legend: 'Waar gaat uw melding over?', +// }, +// render: (args) => ( +//
+// {args.invalid && Geef aan waar uw melding over gaat.} +// +// +// Horecabedrijf +// +// +// Ander soort bedrijf +// +// +// Evenement +// +// +// Iets anders +// +// +//
+// ), +// } From f5c9bc220bc68d3547c74ad00c6bb15f3e888c8e Mon Sep 17 00:00:00 2001 From: Aram Limpens Date: Mon, 3 Jun 2024 16:04:26 +0200 Subject: [PATCH 10/13] Add tests for prefix --- .../react/src/ErrorMessage/ErrorMessage.test.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/react/src/ErrorMessage/ErrorMessage.test.tsx b/packages/react/src/ErrorMessage/ErrorMessage.test.tsx index dbe17b9c39..ec96e3f71d 100644 --- a/packages/react/src/ErrorMessage/ErrorMessage.test.tsx +++ b/packages/react/src/ErrorMessage/ErrorMessage.test.tsx @@ -26,6 +26,20 @@ describe('Error message', () => { expect(component).toHaveClass('ams-error-message extra') }) + it('renders a Dutch prefix by default', () => { + render() + const component = screen.getByText('Invoerfout', { exact: false }) + + expect(component).toBeInTheDocument() + }) + + it('renders a custom prefix', () => { + render() + const component = screen.getByText('Error') + + expect(component).toBeInTheDocument() + }) + it('supports ForwardRef in React', () => { const ref = createRef() From 92f9d0e440fefbcaa7fde5e9466de5a0a1bfc1b5 Mon Sep 17 00:00:00 2001 From: Aram Limpens Date: Mon, 3 Jun 2024 16:10:25 +0200 Subject: [PATCH 11/13] Update readme --- packages/css/src/components/error-message/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/css/src/components/error-message/README.md b/packages/css/src/components/error-message/README.md index 39e61e3765..779ef3cd4e 100644 --- a/packages/css/src/components/error-message/README.md +++ b/packages/css/src/components/error-message/README.md @@ -5,6 +5,7 @@ Show an error message when there is a form field validation error. In the error message explain what went wrong and how to fix it. -See the [Field](/docs/components-forms-field--docs) and [Field Set](/docs/components-forms-field-set--docs) documentation for an explanation and examples of how to use error messages in a form. +For guidance and examples on using error messages in a form, +refer to the [Field](/docs/components-forms-field--docs) and [Field Set](/docs/components-forms-field-set--docs) documentation. Read the documentation by [NL Design System](https://www.nldesignsystem.nl/richtlijnen/formulieren/foutmeldingen) and [Gov.uk](https://design-system.service.gov.uk/components/error-message/) for more information on the contents of error messages and when to show them. From 397dcb8d1ab1b36a90ec66e5f154cab29eb0f257 Mon Sep 17 00:00:00 2001 From: Aram <37216945+alimpens@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:56:57 +0200 Subject: [PATCH 12/13] Update packages/react/src/ErrorMessage/ErrorMessage.tsx Co-authored-by: Vincent Smedinga --- packages/react/src/ErrorMessage/ErrorMessage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react/src/ErrorMessage/ErrorMessage.tsx b/packages/react/src/ErrorMessage/ErrorMessage.tsx index 06cadb51af..3e5841c776 100644 --- a/packages/react/src/ErrorMessage/ErrorMessage.tsx +++ b/packages/react/src/ErrorMessage/ErrorMessage.tsx @@ -9,6 +9,7 @@ import type { ForwardedRef, HTMLAttributes, PropsWithChildren } from 'react' import { VisuallyHidden } from '../VisuallyHidden' export type ErrorMessageProps = { + /** An accessible phrase that screen readers announce before the error message. Should translate to something like ‘input error’. */ prefix?: string } & PropsWithChildren> From 2299f903bc62edf6191b7cbcbf700b39338782e3 Mon Sep 17 00:00:00 2001 From: Aram Limpens Date: Wed, 5 Jun 2024 11:04:11 +0200 Subject: [PATCH 13/13] Render colon by default --- packages/react/src/ErrorMessage/ErrorMessage.test.tsx | 2 +- packages/react/src/ErrorMessage/ErrorMessage.tsx | 7 +++++-- .../src/components/ErrorMessage/ErrorMessage.docs.mdx | 2 +- .../src/components/ErrorMessage/ErrorMessage.stories.tsx | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/react/src/ErrorMessage/ErrorMessage.test.tsx b/packages/react/src/ErrorMessage/ErrorMessage.test.tsx index ec96e3f71d..4026873e78 100644 --- a/packages/react/src/ErrorMessage/ErrorMessage.test.tsx +++ b/packages/react/src/ErrorMessage/ErrorMessage.test.tsx @@ -35,7 +35,7 @@ describe('Error message', () => { it('renders a custom prefix', () => { render() - const component = screen.getByText('Error') + const component = screen.getByText('Error', { exact: false }) expect(component).toBeInTheDocument() }) diff --git a/packages/react/src/ErrorMessage/ErrorMessage.tsx b/packages/react/src/ErrorMessage/ErrorMessage.tsx index 3e5841c776..ce9b2e1c0a 100644 --- a/packages/react/src/ErrorMessage/ErrorMessage.tsx +++ b/packages/react/src/ErrorMessage/ErrorMessage.tsx @@ -15,11 +15,14 @@ export type ErrorMessageProps = { export const ErrorMessage = forwardRef( ( - { children, className, prefix = 'Invoerfout: ', ...restProps }: ErrorMessageProps, + { children, className, prefix = 'Invoerfout', ...restProps }: ErrorMessageProps, ref: ForwardedRef, ) => (

- {prefix} + + {prefix} + {': '} + {children}

), diff --git a/storybook/src/components/ErrorMessage/ErrorMessage.docs.mdx b/storybook/src/components/ErrorMessage/ErrorMessage.docs.mdx index 6f5992b9c9..74fae9a038 100644 --- a/storybook/src/components/ErrorMessage/ErrorMessage.docs.mdx +++ b/storybook/src/components/ErrorMessage/ErrorMessage.docs.mdx @@ -12,7 +12,7 @@ import README from "../../../../packages/css/src/components/error-message/README ## With a custom prefix -Error messages are automatically prefixed with a visually hidden text, the Dutch phrase "Invoerfout: ". +Error messages are automatically prefixed with a visually hidden text, the Dutch word "Invoerfout". This makes the error message more clear for screen reader users. If you want to change this prefix, to support another language for example, you can use the `prefix` prop. diff --git a/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx b/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx index 86095bff6a..8e6c3e4312 100644 --- a/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx +++ b/storybook/src/components/ErrorMessage/ErrorMessage.stories.tsx @@ -28,6 +28,6 @@ export const Default: Story = {} export const WithCustomPrefix: Story = { args: { children: 'Enter an email address in the correct format, like name@example.com', - prefix: 'Error: ', + prefix: 'Error', }, }