From 8453e121d79ac9376dd82d2d5e80f44388fc73d8 Mon Sep 17 00:00:00 2001 From: mfo Date: Tue, 9 Apr 2024 16:19:54 +0200 Subject: [PATCH] feat(champ.errors): add aria-labelledby error on champs wrapped within a fieldset, make error messages always present and aria-live: assertive on validation error Co-authored-by: Corinne Durrmeyer Co-authored-by: Colin Darie --- app/components/dsfr/input_errorable.rb | 9 ++++++++- app/components/dsfr/input_status_message_component.rb | 8 ++------ .../input_status_message_component.html.haml | 2 +- .../editable_champ/editable_champ_component.rb | 2 +- .../editable_champ_component.html.haml | 2 +- app/models/champ.rb | 2 +- 6 files changed, 14 insertions(+), 11 deletions(-) diff --git a/app/components/dsfr/input_errorable.rb b/app/components/dsfr/input_errorable.rb index 1510f210d..afcd8b16a 100644 --- a/app/components/dsfr/input_errorable.rb +++ b/app/components/dsfr/input_errorable.rb @@ -34,6 +34,14 @@ module Dsfr errors.full_messages_for(attribute_or_rich_body) end + def fieldset_error_opts + if dsfr_champ_container == :fieldset && errors_on_attribute? + { aria: { labelledby: "#{describedby_id} #{object.labelledby_id}" } } + else + {} + end + end + private # lookup for edge case from `form.rich_text_area` @@ -73,7 +81,6 @@ module Dsfr 'fr-input': true, 'fr-mb-0': true }.merge(input_error_class_names))) - if errors_on_attribute? @opts.deep_merge!(aria: { describedby: describedby_id diff --git a/app/components/dsfr/input_status_message_component.rb b/app/components/dsfr/input_status_message_component.rb index 608ea19d6..545a6a68e 100644 --- a/app/components/dsfr/input_status_message_component.rb +++ b/app/components/dsfr/input_status_message_component.rb @@ -1,14 +1,10 @@ module Dsfr class InputStatusMessageComponent < ApplicationComponent - def initialize(errors_on_attribute:, error_full_messages:, described_by:, champ:) + def initialize(errors_on_attribute:, error_full_messages:, describedby_id:, champ:) @errors_on_attribute = errors_on_attribute @error_full_messages = error_full_messages - @described_by = described_by + @describedby_id = describedby_id @champ = champ end - - def render? - @errors_on_attribute - end end end diff --git a/app/components/dsfr/input_status_message_component/input_status_message_component.html.haml b/app/components/dsfr/input_status_message_component/input_status_message_component.html.haml index 9edef67b1..305d2d07f 100644 --- a/app/components/dsfr/input_status_message_component/input_status_message_component.html.haml +++ b/app/components/dsfr/input_status_message_component/input_status_message_component.html.haml @@ -1,4 +1,4 @@ -.fr-messages-group{ id: @describedby_id } +.fr-messages-group{ id: @describedby_id, aria: { live: :assertive } } - if @error_full_messages.size > 0 %p{ class: class_names('fr-message' => true, "fr-message--#{@errors_on_attribute ? 'error' : 'valid'}" => true) } = "« #{@champ.libelle} » " diff --git a/app/components/editable_champ/editable_champ_component.rb b/app/components/editable_champ/editable_champ_component.rb index efe61137d..3e3177a19 100644 --- a/app/components/editable_champ/editable_champ_component.rb +++ b/app/components/editable_champ/editable_champ_component.rb @@ -34,7 +34,7 @@ class EditableChamp::EditableChampComponent < ApplicationComponent }.merge(champ_component.input_group_error_class_names) ), data: { controller: stimulus_controller, **data_dependent_conditions, **stimulus_values } - } + }.deep_merge(champ_component.fieldset_error_opts) end def fieldset_element_attributes diff --git a/app/components/editable_champ/editable_champ_component/editable_champ_component.html.haml b/app/components/editable_champ/editable_champ_component/editable_champ_component.html.haml index 11ec41351..84c45bb17 100644 --- a/app/components/editable_champ/editable_champ_component/editable_champ_component.html.haml +++ b/app/components/editable_champ/editable_champ_component/editable_champ_component.html.haml @@ -5,6 +5,6 @@ = render champ_component - = render Dsfr::InputStatusMessageComponent.new(errors_on_attribute: champ_component.errors_on_attribute?, error_full_messages: champ_component.error_full_messages, described_by: @champ.describedby_id, champ: @champ) + = render Dsfr::InputStatusMessageComponent.new(errors_on_attribute: champ_component.errors_on_attribute?, error_full_messages: champ_component.error_full_messages, describedby_id: @champ.describedby_id, champ: @champ) = @form.hidden_field :id, value: @champ.id diff --git a/app/models/champ.rb b/app/models/champ.rb index c8de9dd48..444e5beab 100644 --- a/app/models/champ.rb +++ b/app/models/champ.rb @@ -188,7 +188,7 @@ class Champ < ApplicationRecord end def describedby_id - "#{html_id}-description" if description.present? + "#{html_id}-describedby_id" end def log_fetch_external_data_exception(exception)