fix: resolve Svelte a11y warnings and unused CSS Replace non-interactive `<li role="button">` with proper `<button>` elements in all suggestion lists (upload, detail page, ImageViewer). Replace `<li role="option">` with `<button role="option" aria-selected>` in browse page filter dropdowns. Remove unused CSS selectors. Assisted-by: Crush:deepseek-v4-flash
Maxwell Jensen maxwelljensen@posteo.net
Thu, 14 May 2026 09:29:12 +0200
4 files changed,
53 insertions(+),
33 deletions(-)
M
web/src/lib/ImageViewer.svelte
→
web/src/lib/ImageViewer.svelte
@@ -12,7 +12,7 @@ initialIndex?: number;
onclose: () => void; } = $props(); - let currentIndex = $state(initialIndex); + let currentIndex = $state(0 + initialIndex); let loading = $state(true); let showControls = $state(true); let tagDetails = $state<TagDetail[]>([]);@@ -268,11 +268,11 @@ onblur={() => setTimeout(() => { showSuggestions = false; }, 200)}
disabled={tagBusy} /> {#if showSuggestions} - <ul class="viewer-suggestions"> + <div class="viewer-suggestions"> {#each suggestions as s} - <li role="button" tabindex="0" onmousedown={() => selectSuggestion(s)}>{s}</li> + <button type="button" class="viewer-sug-btn" onmousedown={() => selectSuggestion(s)}>{s}</button> {/each} - </ul> + </div> {/if} </div> <button class="viewer-tag-btn add" onclick={handleAddTags} disabled={tagBusy}>ADD</button>@@ -596,22 +596,27 @@ right: 0;
background: #1a1a1a; border: 1px solid rgba(255, 255, 255, 0.2); border-top: none; - list-style: none; margin: 0; padding: 0; z-index: 15; max-height: 120px; overflow-y: auto; } - .viewer-suggestions li { + .viewer-sug-btn { + display: block; + width: 100%; + text-align: left; padding: 0.3rem 0.5rem; - cursor: pointer; + border: none; + background: none; font-family: 'Inter', sans-serif; font-size: 0.75rem; font-weight: 500; color: #fff; + cursor: pointer; + border-radius: 0; } - .viewer-suggestions li:hover { + .viewer-sug-btn:hover { background: #c62828; } .viewer-tag-btn {
M
web/src/routes/browse/+page.svelte
→
web/src/routes/browse/+page.svelte
@@ -165,14 +165,14 @@ onkeydown={(e) => { if (e.key === 'Enter') applyFilter(); }}
onblur={() => setTimeout(() => { showTagSugs = false; }, 200)} /> {#if showTagSugs} - <ul class="sugs" role="listbox"> + <div class="sugs" role="listbox"> {#each tagSuggestions as s} - <li role="option" tabindex="0" onmousedown={() => selectTagSug(s)}> + <button type="button" role="option" aria-selected={false} class="sug-opt" onmousedown={() => selectTagSug(s)}> <span class="sug-label">{s.tag}</span> <span class="sug-count">{s.usage_count}</span> - </li> + </button> {/each} - </ul> + </div> {/if} </div> <div class="sug-wrap">@@ -185,14 +185,14 @@ onkeydown={(e) => { if (e.key === 'Enter') applyFilter(); }}
onblur={() => setTimeout(() => { showUploaderSugs = false; }, 200)} /> {#if showUploaderSugs} - <ul class="sugs" role="listbox"> + <div class="sugs" role="listbox"> {#each uploaderSuggestions as s} - <li role="option" tabindex="0" onmousedown={() => selectUploaderSug(s)}> + <button type="button" role="option" aria-selected={false} class="sug-opt" onmousedown={() => selectUploaderSug(s)}> <span class="sug-label">{s.tag}</span> <span class="sug-count">{s.usage_count}</span> - </li> + </button> {/each} - </ul> + </div> {/if} </div> <button class="btn" onclick={applyFilter}>FILTER</button>@@ -326,18 +326,23 @@ border-top: none;
max-height: 220px; overflow-y: auto; } - .sugs li { + .sug-opt { display: flex; align-items: center; justify-content: space-between; + width: 100%; + text-align: left; padding: 0.45rem 0.75rem; - cursor: pointer; + border: none; + background: none; font-family: 'Inter', sans-serif; font-size: 0.82rem; font-weight: 500; gap: 0.5rem; + cursor: pointer; + border-radius: 0; } - .sugs li:hover { + .sug-opt:hover { background: #f0f0f0; } .sug-label {
M
web/src/routes/image/[id]/+page.svelte
→
web/src/routes/image/[id]/+page.svelte
@@ -164,11 +164,11 @@ oninput={onTagInput}
onblur={() => setTimeout(() => { showSuggestions = false; }, 200)} /> {#if showSuggestions} - <ul class="suggestions"> + <div class="suggestions"> {#each suggestions as s} - <li role="button" tabindex="0" onmousedown={() => selectSuggestion(s)}>{s}</li> + <button type="button" class="sug-btn" onmousedown={() => selectSuggestion(s)}>{s}</button> {/each} - </ul> + </div> {/if} </div> <button class="tag-btn add" onclick={handleAddTags}>ADD</button>@@ -403,21 +403,26 @@ right: 0;
background: #fff; border: 2px solid #1a1a1a; border-top: none; - list-style: none; margin: 0; padding: 0; z-index: 10; max-height: 130px; overflow-y: auto; } - .suggestions li { + .sug-btn { + display: block; + width: 100%; + text-align: left; padding: 0.35rem 0.5rem; - cursor: pointer; + border: none; + background: none; font-family: 'Inter', sans-serif; font-size: 0.78rem; font-weight: 500; + cursor: pointer; + border-radius: 0; } - .suggestions li:hover { + .sug-btn:hover { background: #f0f0f0; } .tag-btn {
M
web/src/routes/upload/+page.svelte
→
web/src/routes/upload/+page.svelte
@@ -149,11 +149,11 @@ onblur={() => setTimeout(() => { showSuggestions = false; }, 200)}
disabled={loading} /> {#if showSuggestions} - <ul class="suggestions"> + <div class="suggestions"> {#each suggestions as s} - <li role="button" tabindex="0" onmousedown={() => selectSuggestion(s)}>{s}</li> + <button type="button" class="sug-btn" onmousedown={() => selectSuggestion(s)}>{s}</button> {/each} - </ul> + </div> {/if} </div> </label>@@ -268,21 +268,26 @@ right: 0;
background: #fff; border: 2px solid #1a1a1a; border-top: none; - list-style: none; margin: 0; padding: 0; z-index: 10; max-height: 150px; overflow-y: auto; } - .suggestions li { + .sug-btn { + display: block; + width: 100%; + text-align: left; padding: 0.45rem 0.75rem; - cursor: pointer; + border: none; + background: none; font-family: 'Inter', sans-serif; font-size: 0.85rem; font-weight: 500; + cursor: pointer; + border-radius: 0; } - .suggestions li:hover { + .sug-btn:hover { background: #f0f0f0; }