fix(quick-260921-bi2): a11y - Rollen, Semantik, Tab-Reihenfolge (32er-Rest, Teil 1/2)
Vier der fuenf noch offenen Regeln aus Teillieferung B bereinigt:
- noRedundantRoles (4): ueberfluessige role-Angaben auf button/time/select
entfernt (maschineller --unsafe-Fix, gelesen).
- useAriaPropsForRole (1): entfaellt automatisch mit obigem Fix -- das
<select role="combobox"> in search-widget.tsx verlangte die fehlenden
ARIA-Attribute nur wegen der ueberfluessigen Rolle.
- useSemanticElements (4): admin-sidebar/settings-sidebar tragen role=
"navigation" jetzt am <nav> statt am <aside> (kein doppeltes Landmark
mehr); widget-wrapper.tsx ist jetzt ein echtes <article> statt
div role="article"; DropZone.tsx trennt die Datei-Entfernen-Schaltflaeche
als Geschwister ab, damit die Drop-Flaeche selbst ein echtes <button>
werden kann (ein <button> darf kein zweites <button> verschachteln).
Die Drop-Flaeche traegt darum jetzt Klick- UND Drag-Handler direkt am
<button>, sonst waere sie ein "statisches" Element mit Ereignis-Handlern
geworden (die zurueckgestellten Regeln noStaticElementInteractions /
noNoninteractiveElementInteractions waeren neu angeschlagen -- geprueft,
bleiben bei 5/11).
- noNoninteractiveTabindex (1): calculator-widget.tsx traegt jetzt
tabIndex={-1} statt {0}. Die Zifferntasten sind bereits echte <button>
und damit selbst Teil der Tab-Reihenfolge; Tastendruecke erreichen
handleKeyboard weiterhin per Bubbling, sobald eine Taste fokussiert ist.
Verhalten unveraendert, nur ein wirkungsloser Tab-Stopp auf dem Container
selbst entfaellt.
Verbleibend: noLabelWithoutControl (22), naechster Schritt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
This commit is contained in:
@@ -33,18 +33,18 @@ export function SettingsSidebar() {
|
||||
};
|
||||
|
||||
return (
|
||||
<aside
|
||||
className="flex w-[220px] shrink-0 flex-col border-r border-sidebar-border bg-sidebar"
|
||||
role="navigation"
|
||||
aria-label={t('navLabel')}
|
||||
>
|
||||
// a11y/useSemanticElements: role="navigation" nicht auf das <aside> gehoben --
|
||||
// darunter stehen zwei <nav>-Bereiche (Allgemein, Dashboard); ein drittes
|
||||
// Navigations-Landmark auf dem Rahmen waere doppelt. Jedes <nav> traegt
|
||||
// stattdessen die Beschriftung seiner eigenen Kategorie.
|
||||
<aside className="flex w-[220px] shrink-0 flex-col border-r border-sidebar-border bg-sidebar">
|
||||
{/* Allgemein category — above Dashboard (Surface C, 07-06) */}
|
||||
<div className="p-4 pb-2">
|
||||
<h2 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
{t('categoryGeneral')}
|
||||
</h2>
|
||||
</div>
|
||||
<nav className="mb-2 flex flex-col gap-1 px-3">
|
||||
<nav className="mb-2 flex flex-col gap-1 px-3" aria-label={t('categoryGeneral')}>
|
||||
<Link
|
||||
href="/settings/general/account"
|
||||
className={`flex items-center rounded-md px-2 py-1.5 text-sm transition-colors ${
|
||||
@@ -79,7 +79,7 @@ export function SettingsSidebar() {
|
||||
{t('categoryDashboard')}
|
||||
</h2>
|
||||
</div>
|
||||
<nav className="flex flex-col gap-1 px-3">
|
||||
<nav className="flex flex-col gap-1 px-3" aria-label={t('categoryDashboard')}>
|
||||
{items.map((item) => (
|
||||
<Link
|
||||
key={item.href}
|
||||
|
||||
Reference in New Issue
Block a user