feat: Add WCAG-compliant handling for boolean custom fields

This commit is contained in:
carla 2025-12-23 17:02:07 +01:00
parent e3ff3e610c
commit 4e101ea36e
2 changed files with 24 additions and 4 deletions

View file

@ -333,7 +333,8 @@ defmodule MvWeb.CoreComponents do
attr :error_class, :string, default: nil, doc: "the input error class to use over defaults" attr :error_class, :string, default: nil, doc: "the input error class to use over defaults"
attr :rest, :global, attr :rest, :global,
include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength include:
~w(accept autocomplete aria-required capture cols disabled form list max maxlength min minlength
multiple pattern placeholder readonly required rows size step) multiple pattern placeholder readonly required rows size step)
def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
@ -353,6 +354,24 @@ defmodule MvWeb.CoreComponents do
Phoenix.HTML.Form.normalize_value("checkbox", assigns[:value]) Phoenix.HTML.Form.normalize_value("checkbox", assigns[:value])
end) end)
# For checkboxes, we don't use HTML required attribute (means "must be checked")
# Instead, we use aria-required for screen readers (WCAG 2.1, Success Criterion 3.3.2)
# Extract required from rest and remove it, but keep aria-required if provided
rest = assigns.rest || %{}
is_required = Map.get(rest, :required, false)
aria_required = Map.get(rest, :aria_required, if(is_required, do: "true", else: nil))
# Remove required from rest (we don't want HTML required on checkbox)
rest_without_required = Map.delete(rest, :required)
# Ensure aria-required is set if field is required
rest_final =
if aria_required,
do: Map.put(rest_without_required, :aria_required, aria_required),
else: rest_without_required
assigns = assign(assigns, :rest, rest_final)
assigns = assign(assigns, :is_required, is_required)
~H""" ~H"""
<fieldset class="mb-2 fieldset"> <fieldset class="mb-2 fieldset">
<label> <label>
@ -367,9 +386,9 @@ defmodule MvWeb.CoreComponents do
class={@class || "checkbox checkbox-sm"} class={@class || "checkbox checkbox-sm"}
{@rest} {@rest}
/>{@label}<span />{@label}<span
:if={@rest[:required]} :if={@is_required}
class="text-red-700 tooltip tooltip-right" class="text-red-700 tooltip tooltip-right"
data-tip={gettext("This field cannot be empty")} data-tip={gettext("This field is required")}
>*</span> >*</span>
</span> </span>
</label> </label>

View file

@ -144,7 +144,8 @@ defmodule MvWeb.MemberLive.Form do
field={value_form[:value]} field={value_form[:value]}
label={cf.name} label={cf.name}
type={custom_field_input_type(cf.value_type)} type={custom_field_input_type(cf.value_type)}
required={cf.required} required={if cf.value_type == :boolean, do: false, else: cf.required}
aria-required={if cf.required, do: "true", else: nil}
/> />
</.inputs_for> </.inputs_for>
<input <input