fix theme editor radio buttons: accessibility and double dots

Wrap logo mode radios in fieldset/legend for screen reader grouping.
Hide native radio input properly (was using nonexistent .hidden class),
add aria-hidden on decorative dot spans, focus-visible ring on cards,
and IDs on each input.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey 2026-03-04 00:14:57 +00:00
parent 2e5217b010
commit 1a2a6f5d56
3 changed files with 62 additions and 45 deletions

View File

@ -103,7 +103,7 @@ On-site editing overlay for admins: browse the real shop with a sidebar for them
| # | Task | Est | Status | | # | Task | Est | Status |
|---|---|---|---| |---|---|---|---|
| 1 | Fix double radio button dots in theme editor | 30m | planned | | 1 | Fix double radio button dots in theme editor | 30m | done |
### Platform site ### Platform site

View File

@ -4024,7 +4024,14 @@
} }
/* Radio card selector (logo mode picker) */ /* Radio card selector (logo mode picker) */
.theme-radio-fieldset {
border: none;
padding: 0;
margin: 0;
}
.theme-radio-card { .theme-radio-card {
position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 0.75rem; gap: 0.75rem;
@ -4037,6 +4044,17 @@
&:hover { &:hover {
border-color: var(--admin-text-ghost); border-color: var(--admin-text-ghost);
} }
&:has(:focus-visible) {
outline: 2px solid var(--t-accent);
outline-offset: 2px;
}
}
.theme-radio-input {
position: absolute;
opacity: 0;
pointer-events: none;
} }
.theme-radio-card-active { .theme-radio-card-active {

View File

@ -90,9 +90,9 @@
<!-- Branding Section --> <!-- Branding Section -->
<div class="theme-panel"> <div class="theme-panel">
<label class="theme-section-label">Logo & header</label> <fieldset class="theme-radio-fieldset">
<legend class="theme-section-label">Logo & header</legend>
<!-- Logo Mode Radio Cards -->
<div class="admin-stack admin-stack-sm theme-field"> <div class="admin-stack admin-stack-sm theme-field">
<%= for {value, title, desc} <- [ <%= for {value, title, desc} <- [
{"text-only", "Shop name only", "Your name in the heading font"}, {"text-only", "Shop name only", "Your name in the heading font"},
@ -101,31 +101,29 @@
] do %> ] do %>
<label class={[ <label class={[
"theme-radio-card", "theme-radio-card",
if(@theme_settings.logo_mode == value, @theme_settings.logo_mode == value && "theme-radio-card-active"
do: "theme-radio-card-active",
else: ""
)
]}> ]}>
<input <input
type="radio" type="radio"
id={"logo-mode-#{value}"}
name="logo_mode" name="logo_mode"
value={value} value={value}
checked={@theme_settings.logo_mode == value} checked={@theme_settings.logo_mode == value}
phx-click="update_setting" phx-click="update_setting"
phx-value-field="logo_mode" phx-value-field="logo_mode"
phx-value-setting_value={value} phx-value-setting_value={value}
class="hidden" class="theme-radio-input"
/> />
<span class={[ <span
class={[
"theme-radio-dot", "theme-radio-dot",
@theme_settings.logo_mode == value && "theme-radio-dot-active" @theme_settings.logo_mode == value && "theme-radio-dot-active"
]}> ]}
aria-hidden="true"
>
<span class={[ <span class={[
"theme-radio-dot-inner", "theme-radio-dot-inner",
if(@theme_settings.logo_mode == value, @theme_settings.logo_mode == value && "theme-radio-dot-inner-active"
do: "theme-radio-dot-inner-active",
else: ""
)
]}> ]}>
</span> </span>
</span> </span>
@ -136,6 +134,7 @@
</label> </label>
<% end %> <% end %>
</div> </div>
</fieldset>
<!-- Logo Upload (for logo-text and logo-only modes) --> <!-- Logo Upload (for logo-text and logo-only modes) -->
<%= if @theme_settings.logo_mode in ["logo-text", "logo-only"] do %> <%= if @theme_settings.logo_mode in ["logo-text", "logo-only"] do %>