Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@
## 2026-06-09 - Empty State Feedback
**Learning:** When a list or process finishes with zero results, an empty summary container gives no feedback, leaving the user wondering if it actually ran or failed silently.
**Action:** Always provide a helpful empty state message explaining why no results might have occurred, using styles consistent with other hints to offer guidance without showing as an error.
## 2026-10-26 - Semantic Grouping over ARIA Workarounds
**Learning:** Prioritizing native semantic HTML (`<fieldset>` and `<legend>`) over generic `<div>` elements with ARIA attributes (`role="radiogroup"`, `aria-labelledby`) for form groups provides more robust accessibility out of the box, reduces markup bloat, and aligns with HTML standards.
**Action:** Always use `<fieldset>` to group related form controls (like radio buttons or mode selectors) and `<legend>` for their label. If custom styling is needed, reset default browser styles (`border: none`, `margin: 0`, `padding: 0`) rather than resorting to non-semantic wrappers.
4 changes: 2 additions & 2 deletions biome.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.16/schema.json",
"$schema": "https://biomejs.dev/schemas/2.5.0/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
Expand Down Expand Up @@ -33,7 +33,7 @@
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"preset": "recommended",
"suspicious": {
"noExplicitAny": "off",
"noImplicitAnyLet": "off"
Expand Down
16 changes: 15 additions & 1 deletion popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,21 @@ input[type="password"]:focus {
margin-bottom: 8px;
}

.setting-row label {
fieldset {
border: none;
margin: 0;
padding: 0;
}

legend {
display: block;
font-size: 12px;
color: #94a3b8;
margin-bottom: 6px;
}

.setting-row label,
.setting-row legend {
margin-bottom: 4px;
}

Expand Down
24 changes: 12 additions & 12 deletions popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,34 @@ <h1>Jules Task Archiver</h1>

<section class="options">
<h2>Options</h2>
<div class="setting-row">
<label id="opModeLabel">Operation</label>
<div class="segmented" id="opMode" role="group" aria-labelledby="opModeLabel">
<fieldset class="setting-row">
<legend id="opModeLabel">Operation</legend>
<div class="segmented" id="opMode">
<button type="button" data-value="archive" class="active" aria-pressed="true">Archive Tasks</button>
<button type="button" data-value="suggestions" aria-pressed="false">Start Suggestions</button>
</div>
</div>
<div class="setting-row">
<label id="execModeLabel">Execution Mode</label>
<div class="radio-group" role="radiogroup" aria-labelledby="execModeLabel">
</fieldset>
<fieldset class="setting-row">
<legend id="execModeLabel">Execution Mode</legend>
<div class="radio-group">
<label><input type="radio" name="mode" value="dry" checked /> Dry Run</label>
<label><input type="radio" name="mode" value="run" /> Run</label>
</div>
</div>
</fieldset>
<div class="setting-row">
<label class="checkbox">
<input type="checkbox" id="force" aria-describedby="forceHint" />
Force
</label>
<span class="hint" id="forceHint" style="display: block; margin-left: 20px; margin-top: 2px;">Archive every task, ignoring state and matching open Pull Requests</span>
</div>
<div class="setting-row">
<label id="scopeLabel">Scope</label>
<div class="radio-group" role="radiogroup" aria-labelledby="scopeLabel">
<fieldset class="setting-row">
<legend id="scopeLabel">Scope</legend>
<div class="radio-group">
<label><input type="radio" name="scope" value="current" /> Current tab</label>
<label><input type="radio" name="scope" value="all" checked /> All Jules tabs</label>
</div>
</div>
</fieldset>
</section>

<section class="settings">
Expand Down
12 changes: 7 additions & 5 deletions tests/popup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -435,11 +435,13 @@ describe('popup.html accessibility', () => {
)
})

it('should use explicit visible labels for radio groups via aria-labelledby', () => {
assert.ok(popupHtml.includes('id="execModeLabel"'), 'execModeLabel should exist')
assert.ok(popupHtml.includes('aria-labelledby="execModeLabel"'), 'mode radiogroup should use aria-labelledby')
assert.ok(popupHtml.includes('id="scopeLabel"'), 'scopeLabel should exist')
assert.ok(popupHtml.includes('aria-labelledby="scopeLabel"'), 'scope radiogroup should use aria-labelledby')
it('should use explicit semantic fieldsets and legends for grouped controls', () => {
assert.ok(popupHtml.includes('<fieldset class="setting-row">'), 'should use fieldset for grouped controls')
assert.ok(
popupHtml.includes('<legend id="execModeLabel">Execution Mode</legend>'),
'should use semantic legend for execution mode'
)
assert.ok(popupHtml.includes('<legend id="scopeLabel">Scope</legend>'), 'should use semantic legend for scope')
})
})

Expand Down