A list of a form's errors after a failed submit, with a link to each field.
Mirrors ErrorSummary from @digdir/designsystemet-react.
Each error shows up twice: under its field, and as a link to that field in the summary. Keep one list of errors and read both from it:
emailField : ErrorSummary.FieldId
emailField =
ErrorSummary.fieldId "email"
validate : Model -> List ErrorSummary.Error
validate model =
if String.contains "@" model.email then
[]
else
[ { field = emailField, message = "Skriv inn en gyldig e-postadresse" } ]
view : Model -> Html Msg
view model =
Html.form [ Events.onSubmit Submitted ]
[ ErrorSummary.view
{ heading = "Du må rette disse feilene før du kan sende inn"
, level = ErrorSummary.H2
, errors = model.errors
}
[]
, Textfield.new (Ds.label "E-post")
|> Textfield.withError (ErrorSummary.messageFor emailField model.errors)
|> Textfield.view
[ ErrorSummary.linkTarget emailField
, Attr.value model.email
, Events.onInput ChangedEmail
]
]The FieldId ties the link to its field, and
messageFor gives the field the same message. Set
model.errors on submit, not while the user types: <ds-error-summary> takes
focus when it appears, so screen readers announce it at once.
<ErrorSummary> → ErrorSummary.view { … } []<ErrorSummary.Heading> → heading and level<ErrorSummary.List> + .Item + .Link → errors<ErrorSummary.Link href="#email"> → { field = ErrorSummary.fieldId "email", … }role="group", tabindex="-1" and aria-labelledby on
<ds-error-summary>id on the headingBrowser.applicationThe links are plain <a href="#email"> anchors. In a Browser.application
every link click goes to your onUrlRequest, so the browser won't jump to the
field. Move focus there in update:
LinkClicked (Browser.Internal url) ->
case url.fragment of
Just id ->
( model, Task.attempt (\_ -> NoOp) (Browser.Dom.focus id) )
Nothing ->
( model, Nav.pushUrl model.key (Url.toString url) )The summary's heading level. No H1: the page already has one, and
<ds-error-summary> only takes its name from an h2–h6.
The id of a field that can have an error. A separate type, so the
summary's link and its field are built from the same value.
The id as a string, for Browser.Dom.focus and the like.
Sets the id on the input, select or textarea the error is about, so the
summary's link jumps there.
Checkbox.view [ ErrorSummary.linkTarget termsField, Attr.checked model.terms ]
A
<ds-error-summary class="ds-error-summary">with a heading and a list of links. The attributes go on<ds-error-summary>.Renders nothing when there are no errors, so you can always call it. The summary appears, and takes focus, once there is something to fix.
React defaults to
h2. Here the level is required, as forHeading.