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-presentWARNINGHIGH4 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-configuredWARNINGHIGH5 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-configuredWARNINGHIGH3 PTS
Confirms the app declares a document title and description so pages have meaningful metadata for browsers, search, and sharing.
favicon-presentINFOHIGH2 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-presentWARNINGHIGH3 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-presentWARNINGHIGH3 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-resolveWARNINGHIGH2 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-shellWARNINGHIGH3 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-safeWARNINGHIGH2 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-presentWARNINGHIGH5 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-presentWARNINGHIGH5 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-presentWARNINGHIGH4 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-safeWARNINGMEDIUM3 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-presentWARNINGMEDIUM3 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-suppressedERRORMEDIUM3 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-groupsWARNINGMEDIUM0 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-confirmedWARNINGLOW0 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-guardWARNINGMEDIUM3 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-presentWARNINGHIGH3 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-mountedWARNINGHIGH3 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-runtimeERRORHIGH3 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-presentWARNINGMEDIUM4 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-usefulWARNINGHIGH3 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-presentWARNINGMEDIUM4 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-presentERRORHIGH4 PTS
An error surface that only reports failure strands the user. It needs a wired retry, reload, or navigation control.
not-found-recovery-presentWARNINGHIGH3 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-stateWARNINGMEDIUM4 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-presentERRORHIGH2 PTS
The document root must declare a meaningful lang attribute so assistive technology can select the right voice and hyphenation.
images-have-altERRORHIGH4 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-labelsERRORHIGH4 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-namesERRORHIGH3 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-namesERRORHIGH4 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-namesWARNINGHIGH2 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-saneWARNINGMEDIUM3 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-tabindexERRORHIGH2 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-titleERRORHIGH2 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-semanticERRORMEDIUM4 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-controlsERRORHIGH3 PTS
Nesting a control inside another control produces invalid markup with undefined activation behavior and ambiguous announcements in assistive technology.
custom-controls-have-labelsERRORMEDIUM4 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-announcedWARNINGMEDIUM3 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-worksWARNINGLOW0 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-worksWARNINGLOW0 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-labelsERRORHIGH4 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-renderedERRORMEDIUM4 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-errorsERRORMEDIUM3 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-typeWARNINGHIGH3 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-legendWARNINGMEDIUM2 PTS
Radio groups and fieldsets need a group-level name, otherwise each option is announced without the question it answers.
personal-data-autocomplete-presentWARNINGMEDIUM2 PTS
Autocomplete tokens let browsers and password managers fill known values, which removes the most error-prone typing in any form.
validation-wired-to-formWARNINGMEDIUM2 PTS
An installed validation library that no form is connected to provides no protection: submissions bypass the schema entirely.
input-group-compositionWARNINGMEDIUM0 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-copyWARNINGHIGH3 PTS
Detects leftover framework starter text, placeholder domains, and lorem ipsum that ships to users when a scaffold is never replaced.
metadata-title-description-completeWARNINGMEDIUM3 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-presentINFOHIGH2 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-presentINFOHIGH2 PTS
Checks that robots.txt and a sitemap are served, either as static files or through a framework module that generates them.
responsive-shell-presentWARNINGMEDIUM3 PTS
The app shell should change layout across breakpoints instead of rendering one fixed desktop composition on every viewport.
mobile-overflow-absentWARNINGMEDIUM3 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-motionWARNINGMEDIUM2 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-passesWARNINGMEDIUM2 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-iconINFOMEDIUM2 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-anatomyWARNINGMEDIUM0 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-visibilityWARNINGLOW0 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-passesWARNINGLOW0 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.