-
Notifications
You must be signed in to change notification settings - Fork 10
chore: Add form page examples #2172
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
Merged
VincentSmedinga
merged 39 commits into
develop
from
chore/DES-1358-add-form-page-examples
Oct 8, 2025
Merged
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
3fd0053
chore: Add form page examples
alimpens 23bd6cd
Merge branch 'develop' into chore/DES-1358-add-form-page-examples
alimpens af04f60
Align landing page with product page
alimpens 97a9619
Merge branch 'chore/DES-1358-add-form-page-examples' of https://githu…
alimpens c147d49
Add multiple questions page
alimpens 30a9ab8
Make h1 a bit smaller on multiple questions page
alimpens 283cf60
Merge branch 'develop' of https://github.com/Amsterdam/design-system …
alimpens 03fad0a
Add docs, rename page
alimpens 3fbbc1f
Add validation error docs
alimpens 410246b
Add back link to all form pages
alimpens 3864838
Add links to Field and Field Set
alimpens 38df3fa
Rewrite
alimpens 3923b13
Merge branch 'develop' of https://github.com/Amsterdam/design-system …
alimpens 1553655
Merge branch 'develop' into chore/DES-1358-add-form-page-examples
alimpens 512e40a
Fix lint issues
alimpens 3157b76
Merge branch 'develop' into chore/DES-1358-add-form-page-examples
alimpens 2d7a9e3
Add first form page docs
alimpens 0ec29ed
Remove unnecessary brackets
alimpens c9ffdb7
Use prop for spacing, use correct heading level
alimpens 95bf248
Mostly use spacings from ADS space research
alimpens c52458c
Use props instead of util classes everywhere
alimpens ccfa06c
Display levels slightly larger
alimpens 944e8da
Rename props type
alimpens 0e5b292
Use correct heading level
alimpens abf5550
Merge branch 'develop' into chore/DES-1358-add-form-page-examples
alimpens 3c6b392
Use correct id
alimpens 72e31ee
Add comments
alimpens 360a7df
Add documentation to other pages
alimpens 4cf39ff
Remove braces around arrow function body
VincentSmedinga 2bd7f6e
Add Other category
alimpens 1035211
Make Footer Cell slightly larger
alimpens d982c26
Show examples of optional and required Radio's and Checkboxes
alimpens 2d8d03f
Merge branch 'main' of https://github.com/Amsterdam/design-system int…
alimpens 777ade4
Merge branch 'develop' of https://github.com/Amsterdam/design-system …
alimpens 9576d66
Use new FieldSet prop instead of custom component
alimpens 133faaf
Add more docs
alimpens 37a5022
Merge branch 'develop' into chore/DES-1358-add-form-page-examples
alimpens f2744d9
Comment out guideline for now
alimpens a40c687
Merge branch 'develop' into chore/DES-1358-add-form-page-examples
VincentSmedinga File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
{/* @license CC0-1.0 */} | ||
|
||
import { Meta } from "@storybook/addon-docs/blocks"; | ||
import * as FormStories from "./FormFlow.stories.tsx"; | ||
|
||
<Meta of={FormStories} /> | ||
|
||
# Form Flow | ||
|
||
These examples describe a user-friendly form flow. | ||
Form pages have a minimal header and footer in order to remove distractions. | ||
Start with asking [one thing per page](https://www.gov.uk/service-manual/design/form-structure#start-with-one-thing-per-page). | ||
This can be a single question, or a group of related questions. | ||
|
||
## Landing Page | ||
|
||
Most form flows start with a landing page that explains the process and provides a call to action to start the form flow. | ||
|
||
{/* prettier-ignore */} | ||
{/* | ||
TODO: Decide what we want to do here first. | ||
|
||
## First Form Page | ||
|
||
The first form page is the same as other form pages, with one exception: it does not have a back link. | ||
A back link helps users feel secure that their progress is preserved while moving between form pages. | ||
Since the first form page has no progress to save yet, a back link is unnecessary there. | ||
Additionally, users might reach the first form page from a source other than the landing page, which could make a back link confusing. | ||
|
||
\*/} | ||
|
||
## With One Question | ||
|
||
On a form page with one question, the label or legend for the question is the level 1 heading of the page. | ||
For labels, wrap the `h1` around it. | ||
For legends, wrap it around the `h1`. | ||
|
||
For more information, see [Making labels and legends headings](https://design-system.service.gov.uk/get-started/labels-legends-headings/). | ||
|
||
## With Multiple Questions | ||
|
||
When a form page has multiple questions, place an `h1` outside the `form`-tag, | ||
which describes the group of questions. | ||
|
||
For more information, see [Question pages - Asking complex questions without using hint text](https://design-system.service.gov.uk/patterns/question-pages/#asking-complex-questions-without-using-hint-text) | ||
|
||
## With Validation Error | ||
|
||
If the user’s answers fail validation: | ||
|
||
- show them the page again, with the form fields as the user filled them in | ||
- show an [Invalid Form Alert](/docs/components-forms-invalid-form-alert--docs) at the top of the `main` container, and move keyboard focus to it | ||
- add ‘(X invoerfouten) ’ to the beginning of the page `<title>` so that screen readers announce it immediately (Invalid Form Alert does this automatically) | ||
- show [Error message](/docs/components-forms-error-message--docs) components next to fields with errors | ||
|
||
See the [Field](/docs/components-forms-field--docs#with-validation) and [Field Set](/docs/components-forms-field-set--docs#with-validation) docs on how to mark them as invalid. | ||
|
||
Validate the user’s answers when they click on the submit button. | ||
Generally speaking, avoid validating the information in a field before the user has finished entering it or when they move away from the field. | ||
|
||
For more information: | ||
|
||
- [Recover from validation errors](https://design-system.service.gov.uk/patterns/validation/) | ||
- [Error summary](https://design-system.service.gov.uk/components/error-summary/) | ||
|
||
## References | ||
|
||
- [Gov.uk on question pages](https://design-system.service.gov.uk/patterns/question-pages/) | ||
- [NL Design System on forms](https://nldesignsystem.nl/richtlijnen/formulieren/) |
36 changes: 36 additions & 0 deletions
36
storybook/src/pages/amsterdam/FormFlow/FormFlow.stories.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/** | ||
* @license EUPL-1.2+ | ||
* Copyright Gemeente Amsterdam | ||
*/ | ||
|
||
import { Meta, StoryObj } from '@storybook/react-vite' | ||
|
||
import { LandingPage as LandingPageComponent } from './LandingPage' | ||
import { WithMultipleQuestions as WithMultipleQuestionsComponent } from './WithMultipleQuestions' | ||
import { WithOneQuestion as WithOneQuesionComponent } from './WithOneQuestion' | ||
import { WithValidationError as WithValidationErrorComponent } from './WithValidationError' | ||
|
||
const meta = { | ||
title: 'Pages/Amsterdam.nl/Form Flow', | ||
component: LandingPageComponent, | ||
parameters: { | ||
layout: 'fullscreen', | ||
themes: { themeOverride: 'Spacious' }, | ||
}, | ||
} satisfies Meta<typeof LandingPageComponent> | ||
|
||
export default meta | ||
|
||
export const LandingPage: StoryObj = {} | ||
|
||
export const WithOneQuestion: StoryObj = { | ||
render: () => <WithOneQuesionComponent />, | ||
} | ||
|
||
export const WithMultipleQuestions: StoryObj = { | ||
render: () => <WithMultipleQuestionsComponent />, | ||
} | ||
|
||
export const WithValidationError: StoryObj = { | ||
render: () => <WithValidationErrorComponent />, | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/** | ||
* @license EUPL-1.2+ | ||
* Copyright Gemeente Amsterdam | ||
*/ | ||
|
||
import { CallToActionLink, Grid, Heading, OrderedList, Paragraph } from '@amsterdam/design-system-react' | ||
|
||
import { Layout } from '../common/Layout' | ||
|
||
export const LandingPage = () => ( | ||
<Layout> | ||
<Grid as="main" id="inhoud" paddingBottom="2x-large" paddingTop="large"> | ||
<Grid.Cell span={{ narrow: 4, medium: 5, wide: 7 }} start={{ narrow: 1, medium: 2, wide: 3 }}> | ||
<Heading className="ams-mb-m" level={1}> | ||
Waar u dit formulier voor gebruikt | ||
</Heading> | ||
<Paragraph className="ams-mb-xl" size="large"> | ||
Met dit formulier maakt u een afspraak bij een Stadsloket in Amsterdam of Weesp. | ||
</Paragraph> | ||
|
||
<Heading className="ams-mb-s" level={2}> | ||
De stappen in dit formulier | ||
</Heading> | ||
<OrderedList className="ams-mb-l"> | ||
<OrderedList.Item> | ||
<strong>Afspraak</strong> - Kies waarvoor u een afspraak wilt maken. Kies ook waar u de afspraak wilt | ||
hebben. En wanneer. | ||
</OrderedList.Item> | ||
<OrderedList.Item> | ||
<strong>Uw gegevens</strong> - Vul uw contactgegevens in. | ||
</OrderedList.Item> | ||
<OrderedList.Item> | ||
<strong>Controleren</strong> - Controleer de gegevens die u heeft ingevuld. Verstuur de aanvraag. | ||
</OrderedList.Item> | ||
</OrderedList> | ||
<CallToActionLink href="#">Start het formulier</CallToActionLink> | ||
</Grid.Cell> | ||
</Grid> | ||
</Layout> | ||
) |
106 changes: 106 additions & 0 deletions
106
storybook/src/pages/amsterdam/FormFlow/WithMultipleQuestions.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/** | ||
* @license EUPL-1.2+ | ||
* Copyright Gemeente Amsterdam | ||
*/ | ||
|
||
import { | ||
Button, | ||
Field, | ||
Grid, | ||
Heading, | ||
Label, | ||
Page, | ||
PageHeader, | ||
Paragraph, | ||
StandaloneLink, | ||
TextInput, | ||
} from '@amsterdam/design-system-react' | ||
import { ChevronBackwardIcon } from '@amsterdam/design-system-react-icons' | ||
|
||
import { FormFooter } from './components/FormFooter' | ||
|
||
export const WithMultipleQuestions = () => ( | ||
<Page> | ||
{/* Keep the Page Header as simple as possible, to avoid distractions and to prevent users from accidentally navigating away from the form flow. */} | ||
<PageHeader className="ams-mb-xl" /> | ||
{/* The back link is in its own Grid, because it should be outside of the main section. */} | ||
<Grid className="ams-mb-s"> | ||
<Grid.Cell span={{ narrow: 4, medium: 6, wide: 6 }} start={{ narrow: 1, medium: 2, wide: 3 }}> | ||
{/* | ||
* We add a back link to allow users to navigate between form pages, without having to worry about losing their progress. | ||
* Using the browser back button should also work without losing progress, but users do not always trust it (for some applications, rightfully so). | ||
* For more info, see: https://design-system.service.gov.uk/components/back-link/ | ||
* | ||
* We use a link here instead of a button, because multiple submit buttons in a form can cause unexpected behavior. | ||
* For more info, see: https://adamsilver.io/blog/forms-with-multiple-submit-buttons-are-problematic/ | ||
*/} | ||
<StandaloneLink href="#" icon={ChevronBackwardIcon}> | ||
Vorige vraag | ||
</StandaloneLink> | ||
</Grid.Cell> | ||
</Grid> | ||
<Grid as="main" paddingBottom="2x-large"> | ||
<Grid.Cell span={{ narrow: 4, medium: 6, wide: 6 }} start={{ narrow: 1, medium: 2, wide: 3 }}> | ||
{/* | ||
* We use a header here that is labelled by an aria-hidden heading, so that we communicate a labelled | ||
* section to screen readers, without adding an unnecessary heading to the heading hierarchy. | ||
* Furthermore, if CSS fails to load, we still have a clearly labelled section. | ||
*/} | ||
<header aria-labelledby="form-header" className="ams-mb-m ams-gap-xs"> | ||
<Heading aria-hidden id="form-header" level={2} size="level-4"> | ||
Afspraak maken | ||
</Heading> | ||
{/* | ||
* Start by testing your form without a progress indicator to see if it’s simple enough that users do not need one. | ||
* If you do, use a simple one like this one. | ||
* For more info, see: https://design-system.service.gov.uk/patterns/question-pages/#using-progress-indicators | ||
*/} | ||
<Paragraph>Stap 2 van 3: Uw gegevens</Paragraph> | ||
</header> | ||
<Heading className="ams-mb-m" level={1} size="level-3"> | ||
Contactgegevens | ||
</Heading> | ||
{/* | ||
* Do not use HTML5 form validation, because it is not consistent across browsers and devices, | ||
* and often gives the user too little information. | ||
* Preferably validate user input on the server and return it to the client. | ||
* If that is not possible, use client-side validation. | ||
* For more info, see: https://nldesignsystem.nl/richtlijnen/formulieren/foutmeldingen/html-formuliervalidatie/#gebruik-geen-html-formuliervalidatie | ||
*/} | ||
<form noValidate onSubmit={(e) => e.preventDefault()}> | ||
{/* See the docs on specific form components on https://designsystem.amsterdam for more information on how to use them */} | ||
<Field> | ||
<Label htmlFor="email-input" optional> | ||
E-mailadres | ||
</Label> | ||
<TextInput | ||
autoComplete="email" | ||
autoCorrect="off" | ||
className="ams-mb-m" | ||
id="email-input" | ||
name="email" | ||
size={30} // Based on this recommendation: https://design-system.service.gov.uk/patterns/email-addresses/#help-users-to-enter-a-valid-email-address | ||
spellCheck="false" | ||
type="email" | ||
/> | ||
</Field> | ||
<Field className="ams-mb-l"> | ||
<Label htmlFor="tel-input" optional> | ||
Telefoonnummer | ||
</Label> | ||
<TextInput | ||
autoComplete="tel" | ||
className="ams-mb-m" | ||
id="tel-input" | ||
name="phone" | ||
size={15} // Phone numbers have a maximum length of 15 characters, as per E.164 standard: https://en.wikipedia.org/wiki/E.164 | ||
type="tel" | ||
/> | ||
</Field> | ||
<Button type="submit">Volgende vraag</Button> | ||
</form> | ||
</Grid.Cell> | ||
</Grid> | ||
<FormFooter /> | ||
</Page> | ||
) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.