| 1.1.1 | Non-text Content (Level A) | Supports | All decorative icons (lucide-react) carry aria-hidden. Icon-only buttons (password toggle, navigation menu, row actions, dialog close, etc.) have aria-label. Avatar <img> elements use empty alt because the user's name is rendered alongside. |
| 1.2.1 | Audio-only and Video-only (Prerecorded) (Level A) | Not Applicable | No audio or video content is shipped. |
| 1.2.2 | Captions (Prerecorded) (Level A) | Not Applicable | No prerecorded video content with audio. |
| 1.2.3 | Audio Description or Media Alternative (Prerecorded) (Level A) | Not Applicable | No prerecorded video content. |
| 1.2.4 | Captions (Live) (Level AA) | Not Applicable | No live audio content. |
| 1.2.5 | Audio Description (Prerecorded) (Level AA) | Not Applicable | No prerecorded video content. |
| 1.3.1 | Info and Relationships (Level A) | Supports | Every form (sign-in, sign-up, connection form, bulk-delete, row form, AI settings, team invite, action editor, contact form) uses programmatic label association via htmlFor/id pairs or wrapping <label> elements. As of v3.5.0 the previously-bare labels in TeamMembers, ActionsManager Field helper, and EditableField inline editor were patched. As of v3.10.0 comparison/pricing/admin tables on marketing pages ship explicit scope="col" on every column header. Lists, headings, and landmarks (<nav>, <main>, <header>, <footer>, <aside>) are used semantically. |
| 1.3.2 | Meaningful Sequence (Level A) | Supports | DOM order matches visual order; no CSS reordering creates traversal inconsistencies. Verified across audit. |
| 1.3.3 | Sensory Characteristics (Level A) | Supports | Instructions don't rely solely on color, shape, size, or position. Errors carry icon + text + role="alert". |
| 1.3.4 | Orientation (Level AA) | Supports | Layout works in portrait and landscape; no orientation is forced. |
| 1.3.5 | Identify Input Purpose (Level AA) | Supports | Auth forms set autoComplete=email/current-password/new-password/name. Connection form sets autoComplete=url and inputMode=url for project URL, autoComplete=off for secrets. |
| 1.4.1 | Use of Color (Level A) | Supports | Color is never the sole information carrier. Errors pair red with icons + text; required fields use icon + helper text; status chips use both color and label. |
| 1.4.2 | Audio Control (Level A) | Not Applicable | No auto-playing audio. |
| 1.4.3 | Contrast (Minimum) (Level AA) | Supports | Primary text in both light and dark modes is ≈18:1 against the background. Muted text ≈8.5–9.5:1. Accent and danger tokens clear 4.5:1. As of v3.10.0 the faint-foreground token (microcopy / eyebrow labels) was darkened to clear 4.5:1 in both modes - dark mode now ≈4.6:1, light mode ≈4.7:1. Ratios were computed by inspection of CSS tokens, not measured with axe-core / Lighthouse; customers should run their own automated audit for procurement-grade verification. |
| 1.4.4 | Resize Text (Level AA) | Supports | All sizing uses rem/em via Tailwind utilities. Display sizes use clamp(). No px-pinned text. Text reflows correctly at 200% zoom. |
| 1.4.5 | Images of Text (Level AA) | Supports | Text is rendered as text. No images of text anywhere in the product. |
| 1.4.10 | Reflow (Level AA) | Supports | Responsive across breakpoints (sm/md/lg). Workspace switches to single-column + slide-out nav under md. No 2-D scrolling required at 320 CSS pixels. |
| 1.4.11 | Non-text Contrast (Level AA) | Partially Supports | Focus rings (2px solid accent + 2px offset) and accent buttons clear 3:1. Input/card resting borders are intentionally hairline (≈1.5–1.7:1) - they meet 3:1 only on focus / hover. Compensated by strong focus states; acknowledged below spec on resting state. |
| 1.4.12 | Text Spacing (Level AA) | Supports | No fixed letter-spacing / word-spacing / line-height in px. Containers don't clip text under user-overridden spacing. |
| 1.4.13 | Content on Hover or Focus (Level AA) | Supports | Radix Tooltip is dismissible (Escape), hoverable, persistent. As of v3.5.0 the two remaining title="..." attributes (SignInForm "Forgot?", Topbar "Refresh schema") were replaced with Radix Tooltip instances. |
| 2.1.1 | Keyboard (Level A) | Supports | Every interactive element is a <button>, <a>/<Link>, Radix primitive, or native form control. No click-only divs. Inline-edit fields commit on Enter / cancel on Escape. |
| 2.1.2 | No Keyboard Trap (Level A) | Supports | All modal flows go through Radix Dialog / DropdownMenu / Popover with focus traps + Escape exits. No custom traps. |
| 2.1.4 | Character Key Shortcuts (Level A) | Supports | Cmd/Ctrl-K opens the command palette. No single-character shortcuts that activate without a modifier. |
| 2.2.1 | Timing Adjustable (Level A) | Not Applicable | No time limits on user activity. Session cookies follow standard NextAuth lifetime; sign-out is explicit. |
| 2.2.2 | Pause, Stop, Hide (Level A) | Supports | Decorative motion (footer drifting particles, hero animations) respects prefers-reduced-motion. Spinners are short-lived (loading states); no auto-updating content the user cannot pause. |
| 2.3.1 | Three Flashes or Below Threshold (Level A) | Supports | No flashing content. |
| 2.4.1 | Bypass Blocks (Level A) | Supports | As of v3.5.0, a "Skip to content" link is the first focusable element on every page; it jumps to the <main id="main"> landmark in each layout (public, account, workspace, admin, auth shell). |
| 2.4.2 | Page Titled (Level A) | Supports | Every route exports a <title> via Next.js metadata; template appends "· Suparbase". |
| 2.4.3 | Focus Order (Level A) | Supports | DOM order matches visual order. Modals open with focus on first focusable child; dropdowns return focus to trigger on close (Radix defaults). |
| 2.4.4 | Link Purpose (In Context) (Level A) | Supports | Links use descriptive text or carry aria-label when icon-only ("Suparbase home", "Connection settings", "Open row {value}", etc.). |
| 2.4.5 | Multiple Ways (Level AA) | Supports | Pages are reachable via the primary nav, sitemap (/sitemap.xml), site search (Cmd-K command palette inside the workspace), and explicit links from related pages (blog → use cases → features → pricing, etc.). |
| 2.4.6 | Headings and Labels (Level AA) | Supports | Pages have exactly one <h1> via PageHeader. Section headings step down logically. Form labels are descriptive (no "Field 1" patterns). |
| 2.4.7 | Focus Visible (Level AA) | Supports | Global :focus-visible outline (2px solid accent, 2px offset). Radix wrappers add focus-visible:ring-2 ring-accent. As of v3.5.1 the Button component carries an explicit focus-visible ring (previously its base class disabled the outline without adding a replacement). Initially-hidden controls (e.g., row hover-only actions) reveal on keyboard focus. |
| 2.4.11 | Focus Not Obscured (Minimum) (Level AA) [WCAG 2.2] | Supports | The sticky workspace topbar reserves the top edge of the viewport, but focused interactive elements are not obscured because the browser's scrollIntoView default brings them below the topbar. No custom CSS forces a focused element behind another layer. |
| 2.5.1 | Pointer Gestures (Level A) | Supports | No drag-only or multi-finger gestures. All actions are reachable via single-pointer taps or clicks. |
| 2.5.2 | Pointer Cancellation (Level A) | Supports | Buttons activate on pointerup (browser default), not pointerdown. No custom pointer handling that would defeat cancellation by dragging off. |
| 2.5.3 | Label in Name (Level A) | Supports | Visible text matches accessible name (e.g., "Sign in" button's aria-name is "Sign in"). Icon-only buttons' aria-labels match tooltip text. |
| 2.5.4 | Motion Actuation (Level A) | Not Applicable | No motion-based activation (no shake-to-undo, no tilt gestures). |
| 2.5.7 | Dragging Movements (Level AA) [WCAG 2.2] | Supports | No primary functionality requires a drag gesture. Selection, sorting, and reordering all have click or keyboard equivalents (Radix Select, Dropdown, native checkboxes). |
| 2.5.8 | Target Size (Minimum) (Level AA) [WCAG 2.2] | Supports | Primary action buttons (sign-in, save, delete, upgrade) are well above the 24×24 CSS-pixel minimum. As of v3.10.0 every secondary icon button - filter-chip remove, inline-edit confirm / cancel, password-eye toggle, schema tree expand, dashboard widget controls - was bumped to p-1.5, putting their target areas at ≥24×24 CSS pixels. |
| 3.1.1 | Language of Page (Level A) | Supports | <html lang="en"> on root layout. No alternate-language content shipped. |
| 3.1.2 | Language of Parts (Level AA) | Not Applicable | All content is English. |
| 3.2.1 | On Focus (Level A) | Supports | Focus events never navigate, submit, or change context. Tooltips opening on focus are permitted (dismissible per Radix). |
| 3.2.2 | On Input (Level A) | Supports | Inputs never navigate or submit on change. Forms require explicit submit-button activation. |
| 3.2.3 | Consistent Navigation (Level AA) | Supports | Primary nav, footer, and workspace sidebar are consistent across pages. |
| 3.2.4 | Consistent Identification (Level AA) | Supports | Reused components (delete button, edit button, status chips, plan pills) are identified consistently across the product. |
| 3.2.6 | Consistent Help (Level A) [WCAG 2.2] | Supports | As of v3.10.0 a single /contact form is the canonical help destination, linked from the footer (every page), every legal and docs surface, and the in-app account settings panel. The form preserves the requested topic via query string (?topic=sales, ?topic=security, etc.) so help is reachable from a consistent position regardless of which page the visitor lands on. |
| 3.3.1 | Error Identification (Level A) | Supports | Form-level errors render with role="alert" and an icon. Field-level errors set aria-invalid and link via aria-describedby to the inline message. |
| 3.3.2 | Labels or Instructions (Level A) | Supports | Forms include label + explanatory hint where the format is non-obvious. As of v3.5.0 the previously-bare labels were patched. |
| 3.3.3 | Error Suggestion (Level AA) | Supports | Error messages are specific (e.g., "URL must point to a *.supabase.co project", "Password must be at least 12 characters", password-strength meter with remaining-char count). |
| 3.3.4 | Error Prevention (Legal, Financial, Data) (Level AA) | Supports | Destructive flows (delete row, bulk delete, service-role warning, admin subscription reset, storage bucket delete, agent-session undo, SQL write-mode toggle) all gate behind themed confirmation dialogs as of v3.5.1. Bulk delete and admin reset require typing a confirmation word. Row deletes show a 5-second undo toast. Agent Sentry supports one-click session undo. |
| 3.3.7 | Redundant Entry (Level A) [WCAG 2.2] | Supports | Forms don't ask the user to re-enter information they have already supplied in the same session. Sign-up collects credentials once; multi-step flows (connection creation, action / widget editors) preserve in-progress values. |
| 3.3.8 | Accessible Authentication (Minimum) (Level AA) [WCAG 2.2] | Supports | Authentication uses email + password (bcrypt) or GitHub OAuth. No cognitive function test (image puzzles, recall, transcription) is required. Password fields support browser autocomplete and password managers. Copy / paste is allowed in every credential field. |
| 4.1.2 | Name, Role, Value (Level A) | Supports | Radix primitives handle role / state / value correctly. Custom widgets (password show/hide toggle, advanced-section disclosure, password-strength meter as role="meter") expose state via standard ARIA properties. |
| 4.1.3 | Status Messages (Level AA) | Supports | Toast notifications use sonner's default polite live region. Form alerts use role="alert". As of v3.5.0 the AI chat conversation is marked role="log" aria-live="polite". As of v3.10.0 inline loading-state spinners (Refresh schema, EditableField commit, contact-form submit, route-level skeletons) expose aria-busy or role="status" so screen readers announce loading without stealing focus. |