CATALOG

62 rules

Ruleset 0.1.0. Every rule reports only what it can prove from source. A rule that cannot apply returns not applicable and leaves the score untouched.

Foundation

WEIGHT 20 · 9 RULES · 27 POINTS

  • shadcn-config-present

    WARNINGHIGH4 PTS

    Checks that a components.json file exists at the project root and parses cleanly, so shadcn-vue tooling and alias-aware audits can work.

  • theme-provider-configured

    WARNINGHIGH5 PTS

    Confirms the app ships light/dark theme management: the Nuxt color-mode module, a @vueuse/core useColorMode/useDark composable, or a manual documentElement dark-class toggle.

  • metadata-configured

    WARNINGHIGH3 PTS

    Confirms the app declares a document title and description so pages have meaningful metadata for browsers, search, and sharing.

  • favicon-present

    INFOHIGH2 PTS

    Confirms the app ships a favicon: a public/favicon or icon asset, or an explicit icon <link> in index.html or the Nuxt head config.

  • not-found-route-present

    WARNINGHIGH3 PTS

    Confirms unmatched routes are handled: a Nuxt error.vue page, or a Vue Router catch-all route / NotFound view in the router configuration.

  • error-boundary-present

    WARNINGHIGH3 PTS

    Confirms runtime render errors are caught: a Nuxt error page or <NuxtErrorBoundary>, or a Vue onErrorCaptured hook / app.config.errorHandler in the entry.

  • components-aliases-resolve

    WARNINGHIGH2 PTS

    When components.json configures import aliases, tsconfig.json or jsconfig.json must declare matching compilerOptions.paths so the aliases resolve at build time.

  • theme-provider-mounted-in-shell

    WARNINGHIGH3 PTS

    Confirms theme management is actually wired into the app shell (app.vue/layout or App.vue/main.ts), not merely present somewhere in the codebase.

  • theme-hydration-safe

    WARNINGHIGH2 PTS

    For Nuxt apps, confirms theme state is read in an SSR-safe way: via the color-mode module, or a manual client-side theme read guarded by an inline head script that runs before hydration.

Interaction

WEIGHT 20 · 9 RULES · 26 POINTS

  • theme-hotkey-present

    WARNINGHIGH5 PTS

    A keyboard shortcut should toggle the color theme, guarded so it does not fire while the user is typing in an input, textarea, select, or contenteditable element.

  • command-menu-present

    WARNINGHIGH5 PTS

    A discoverable command palette should be mounted at the app level: the shadcn command module is used and a single template renders the dialog, input, empty state, and command items together.

  • command-menu-hotkey-present

    WARNINGHIGH4 PTS

    The command palette should be reachable via the conventional Cmd/Ctrl+K shortcut that prevents the default action and toggles the menu open.

  • global-hotkeys-are-safe

    WARNINGMEDIUM3 PTS

    Global keydown listeners must be cleaned up on unmount and must not hijack bare printable keys while the user is typing. VueUse listener helpers, which clean up automatically, are treated as safe.

  • mobile-nav-present

    WARNINGMEDIUM3 PTS

    When an app-level navigation shell exists, mobile users need a responsive affordance: a mobile-visibility trigger opening a Sheet/Drawer/Dialog, or a responsive fixed bottom navigation.

  • focus-visible-not-suppressed

    ERRORMEDIUM3 PTS

    Removing the focus outline without a visible replacement makes keyboard navigation invisible. Every `outline-none`/`outline: none` must be paired with a focus-visible indicator.

  • items-belong-to-groups

    WARNINGMEDIUM0 PTS

    Select, dropdown, and command items should be composed inside their content or group wrappers. This advisory highlights items that appear misplaced within a single template.

  • destructive-actions-confirmed

    WARNINGLOW0 PTS

    Destructive controls should be paired with a confirmation or undo affordance so users do not lose data by accident. This advisory flags destructive controls with no correlated confirmation in the same file.

  • typing-target-guard

    WARNINGMEDIUM3 PTS

    A global single-key shortcut should not fire while the user is typing. Handlers bound to the document need a check that the event target is not an input, textarea, select, or contenteditable element.

States

WEIGHT 20 · 9 RULES · 31 POINTS

  • toast-provider-present

    WARNINGHIGH3 PTS

    A recognized toast runtime must be installed and a matching provider element (Toaster/SonnerToaster/UNotifications, or a sonner ui-dir component) must be mounted in a template.

  • toast-provider-mounted

    WARNINGHIGH3 PTS

    A toast provider element must be rendered from an app-shell file (app.vue, App.vue, a layout, or error.vue), not merely present somewhere in the component tree.

  • toast-runtime

    ERRORHIGH3 PTS

    Code that calls toast() needs a toast library installed, otherwise the call resolves to nothing at runtime and the notification silently never appears.

  • route-loading-boundary-present

    WARNINGMEDIUM4 PTS

    Navigations should surface progress: a <NuxtLoadingIndicator> for Nuxt, or a router progress hook / top-level Suspense fallback for lazy-loaded Vue Router routes.

  • suspense-fallback-useful

    WARNINGHIGH3 PTS

    Every <Suspense> element must declare a #fallback template slot containing non-empty content, so users see a real loading affordance while async setup resolves.

  • empty-state-present

    WARNINGMEDIUM4 PTS

    Templates that iterate a script-defined collection with v-for must also render an empty branch (a length-guarded v-if/v-else-if/v-else) so an empty list is not a blank screen.

  • error-state-retry-present

    ERRORHIGH4 PTS

    An error surface that only reports failure strands the user. It needs a wired retry, reload, or navigation control.

  • not-found-recovery-present

    WARNINGHIGH3 PTS

    A not-found page should route the user back into the product through navigation, a back action, or search rather than ending the session.

  • async-action-pending-state

    WARNINGMEDIUM4 PTS

    A form that submits asynchronously without a pending state gives no feedback and allows duplicate submissions on repeated clicks.

Accessibility

WEIGHT 20 · 15 RULES · 40 POINTS

  • html-lang-present

    ERRORHIGH2 PTS

    The document root must declare a meaningful lang attribute so assistive technology can select the right voice and hyphenation.

  • images-have-alt

    ERRORHIGH4 PTS

    Native <img> elements and Nuxt image components must declare alternative text. Bound :alt values pass; missing or empty static alt fails.

  • icon-buttons-have-labels

    ERRORHIGH4 PTS

    A button whose entire content is an icon has no accessible name unless one is supplied explicitly, leaving screen reader users with an unlabelled control.

  • links-have-accessible-names

    ERRORHIGH3 PTS

    A link with no text, no label, and no described image is announced as an anonymous destination and cannot be understood out of context.

  • dialogs-have-accessible-names

    ERRORHIGH4 PTS

    A dialog without a title is announced as an unnamed region, so a screen reader user entering it has no idea what it is for. Covers shadcn-vue dialog, alert dialog, sheet, and drawer surfaces, and the reka-ui primitives beneath them.

  • nav-landmarks-have-names

    WARNINGHIGH2 PTS

    When an app exposes more than one navigation landmark, each needs its own name so screen reader users can tell primary navigation from secondary.

  • heading-structure-sane

    WARNINGMEDIUM3 PTS

    Screen reader users navigate by heading level. A page with no level-one heading, or one that skips levels, produces an outline that cannot be scanned reliably.

  • no-positive-tabindex

    ERRORHIGH2 PTS

    A positive tabindex pulls an element out of document order and forces every other focusable element behind it, which breaks keyboard navigation across the page.

  • iframes-have-title

    ERRORHIGH2 PTS

    An iframe without a title is announced only as "frame", giving no indication of what it contains before a user enters it.

  • interactive-elements-are-semantic

    ERRORMEDIUM4 PTS

    A clickable div is invisible to keyboard and assistive technology unless it declares a role, is focusable, and handles keyboard activation.

  • no-nested-interactive-controls

    ERRORHIGH3 PTS

    Nesting a control inside another control produces invalid markup with undefined activation behavior and ambiguous announcements in assistive technology.

  • custom-controls-have-labels

    ERRORMEDIUM4 PTS

    Controls such as Checkbox, Switch, Slider, and SelectTrigger render no text of their own, so each needs a label, an aria-label, or an aria-labelledby reference.

  • status-messages-announced

    WARNINGMEDIUM3 PTS

    Dynamic status messages should reach assistive technology through a live region or an accessible toast channel, otherwise a sighted user sees the update and a screen reader user does not.

  • dialog-focus-trap-works

    WARNINGLOW0 PTS

    Looks for a focus-managed primitive behind dialog-like surfaces. Focus containment and restoration cannot be proven statically, so this reports what backs the dialog rather than scoring it.

  • keyboard-navigation-works

    WARNINGLOW0 PTS

    Looks for a keyboard-aware primitive behind composite widgets such as menus, tabs, and listboxes. Arrow-key, Home/End, and focus behaviour cannot be proven statically, so this reports what backs the widget rather than scoring it.

Forms and Data Entry

WEIGHT 10 · 8 RULES · 20 POINTS

  • forms-have-labels

    ERRORHIGH4 PTS

    Every data-entry control needs a programmatic label. Placeholder text is not a label and disappears the moment a user starts typing.

  • field-errors-rendered

    ERRORMEDIUM4 PTS

    A validation library that never renders its messages fails silently: the form refuses to submit and the user is given no reason why.

  • invalid-fields-associated-with-errors

    ERRORMEDIUM3 PTS

    A visible error message that is not linked to its control never reaches screen reader users, who hear only that the field is required after submission fails.

  • form-buttons-have-explicit-type

    WARNINGHIGH3 PTS

    A button inside a form defaults to type="submit". Any secondary action without an explicit type silently submits the form when clicked.

  • grouped-controls-have-legend

    WARNINGMEDIUM2 PTS

    Radio groups and fieldsets need a group-level name, otherwise each option is announced without the question it answers.

  • personal-data-autocomplete-present

    WARNINGMEDIUM2 PTS

    Autocomplete tokens let browsers and password managers fill known values, which removes the most error-prone typing in any form.

  • validation-wired-to-form

    WARNINGMEDIUM2 PTS

    An installed validation library that no form is connected to provides no protection: submissions bypass the schema entirely.

  • input-group-composition

    WARNINGMEDIUM0 PTS

    An InputGroup wired with a raw input or textarea loses the padding, focus ring, and addon alignment its own parts provide, so the group renders correctly only by accident.

Production Polish

WEIGHT 10 · 12 RULES · 22 POINTS

  • no-starter-copy

    WARNINGHIGH3 PTS

    Detects leftover framework starter text, placeholder domains, and lorem ipsum that ships to users when a scaffold is never replaced.

  • metadata-title-description-complete

    WARNINGMEDIUM3 PTS

    Every routable page should set its own title and description so search results and browser tabs are not inherited from a generic app-level default.

  • social-preview-present

    INFOHIGH2 PTS

    Checks for Open Graph or Twitter card metadata so links shared in chat apps and social feeds render a title and image instead of a bare URL.

  • public-app-seo-files-present

    INFOHIGH2 PTS

    Checks that robots.txt and a sitemap are served, either as static files or through a framework module that generates them.

  • responsive-shell-present

    WARNINGMEDIUM3 PTS

    The app shell should change layout across breakpoints instead of rendering one fixed desktop composition on every viewport.

  • mobile-overflow-absent

    WARNINGMEDIUM3 PTS

    Fixed pixel widths wider than a small phone viewport cause horizontal scrolling. Responsive-prefixed utilities are exempt because they only apply above a breakpoint.

  • animations-respect-reduced-motion

    WARNINGMEDIUM2 PTS

    Continuous or large-scale animation should be guarded by a reduced-motion preference so users with vestibular sensitivity are not forced into motion.

  • pointer-target-size-passes

    WARNINGMEDIUM2 PTS

    Interactive controls sized below the WCAG 2.2 minimum target area are hard to hit on touch devices. Only statically-sized controls are evaluated.

  • button-icons-have-data-icon

    INFOMEDIUM2 PTS

    Icons rendered inside a labelled control should be hidden from assistive technology so screen readers announce the label once instead of reading icon markup.

  • alert-anatomy

    WARNINGMEDIUM0 PTS

    An Alert should carry an AlertTitle and at most one icon. A title-less alert announces as an unlabelled region, and a second icon competes with the first for meaning.

  • responsive-visibility

    WARNINGLOW0 PTS

    A surface that hides an element at a breakpoint should present the alternative at the complementary range, otherwise one viewport shows nothing where content is expected.

  • color-contrast-passes

    WARNINGLOW0 PTS

    Marks styled colour pairs for browser verification. Computed contrast depends on cascade, theme, and opacity, none of which can be resolved from source, so this reports where to look rather than scoring it.