vuetifyjs/vuetify
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·August 1, 2026
Elevated
Accessibility needs attention.
More findings
Verdict
Vuetify's docs look polished for mouse users but fall apart for anyone else: no keyboard access to copy or playground actions, no focus states, and TOC hit targets too small to tap. The biggest risk is that these gaps compound, since the same hover-only logic repeats across headings, TOC, and code blocks.
Files Rams reviewed
packages/docs/src/components/app/Heading.vue
packages/docs/src/components/app/Link.vue
packages/docs/src/components/app/Markdown.vue
packages/docs/src/components/app/Markup.vue
packages/docs/src/components/app/Toc.vue
packages/docs/src/components/app/TooltipBtn.vue
packages/docs/src/components/app/bar/Bar.vue
packages/docs/src/components/app/bar/EcosystemMenu.vue
packages/docs/src/components/app/bar/LearnMenu.vue
packages/docs/src/components/app/bar/NotificationsMenu.vue
packages/docs/src/components/app/bar/SupportMenu.vue
packages/docs/src/components/app/drawer/Drawer.vue
packages/docs/src/components/app/drawer/PinnedItems.vue
packages/docs/src/components/app/list/List.vue
packages/docs/src/components/app/search/Search.vue
packages/docs/src/components/app/search/SearchDialog.vue
packages/docs/src/components/app/search/SearchGroup.vue
packages/docs/src/components/app/search/SearchResults.vue
packages/docs/src/components/app/settings/options/OfflineOption.vue
packages/docs/src/components/app/settings/options/ThemeOption.vue
packages/docs/src/components/app/BackToTop.vue
packages/docs/src/components/app/Btn.vue
packages/docs/src/components/app/Caption.vue
packages/docs/src/components/app/CommitBtn.vue
packages/docs/src/components/app/Divider.vue
packages/docs/src/components/app/Figure.vue
packages/docs/src/components/app/Headline.vue
packages/docs/src/components/app/Sheet.vue
packages/docs/src/components/app/Table.vue
packages/docs/src/components/app/TextField.vue
Accessibility
packages/docs/src/components/app/Markup.vue:33
Copy and open-in-playground buttons don't exist for keyboard or touch users
Both the copy-source v-btn and the open-code v-btn in Markup.vue are wrapped in `v-if="isHovering"`, so they are removed from the DOM entirely until a mouse hover fires. There's also no `aria-label` set, only a `v-tooltip` for the visible label. A keyboard user tabbing through the page, or any touch-screen user, never triggers `isHovering` and never gets these controls in the tab order at all.
Why it matters
Keyboard and touch users are completely locked out of copying code samples or opening them in the Playground, since the controls never render for them, not even as an unlabeled button.
Fix
Keep interactive controls mounted in the DOM at all times and use CSS opacity/visibility for hover reveal, and give icon-only buttons an explicit aria-label so their name doesn't depend on tooltip hover.
<v-btn
v-if="isHovering"
:key="icon"
:icon="icon"
class="text-disabled me-3 mt-2 app-markup-btn position-absolute right-0 top-0"
density="comfortable"
size="small"
v-bind="activatorProps"
variant="text"
@click="copy"
/><v-btn
:key="icon"
:icon="icon"
:aria-label="t('copy-source')"
:class="['text-disabled me-3 mt-2 app-markup-btn position-absolute right-0 top-0', { 'opacity-0': !isHovering }]"
density="comfortable"
size="small"
v-bind="activatorProps"
variant="text"
@click="copy"
/>packages/docs/src/components/app/Toc.vue:115
Sponsor promotion link has no accessible name at all
The sponsor ad anchor in Toc.vue wraps only a `<v-img :src="spot.spot.image.url" />` with no `alt` attribute and no surrounding text. The link (`<a :href="spot.spot.href" ... target="_blank">`) has zero text content and zero accessible name.
Why it matters
A screen reader user tabbing to this link hears nothing describing where it leads or what it promotes, an unlabeled link in a list of otherwise well-labeled navigation items.
Fix
Every image that is the sole content of a link must carry descriptive alt text so the link has an accessible name.
<v-img :src="spot.spot.image.url" /><v-img :src="spot.spot.image.url" :alt="spot.spot.sponsor ? `Sponsored by ${spot.spot.sponsor}` : 'Sponsor advertisement'" />packages/docs/src/components/app/Heading.vue:7
Heading anchor link hidden from every screen reader user
The deep-link anchor inside Heading.vue (the "#" router-link that lets readers copy a link to a section) is wrapped in aria-hidden="true". That doesn't just hide the decorative '#' glyph, it removes the entire interactive link from the accessibility tree, so a screen reader user has no way to discover or activate it at all.
Why it matters
Sighted mouse users can hover to reveal and copy section links; screen reader users are silently denied the same capability, making deep-linking to documentation sections a sighted-only feature.
Fix
Never apply aria-hidden to an element that contains the only instance of an interactive control; hide decorative glyphs individually and give the link an accessible name instead.
<router-link
v-if="href"
:to="href"
aria-hidden="true"
class="text-decoration-none text-end text-md-start d-none d-sm-inline-block"
style="user-select: none"
>
<span class="text-primary">#</span>
</router-link><router-link
v-if="href"
:to="href"
:aria-label="t('copy-link-to-section')"
class="text-decoration-none text-end text-md-start d-none d-sm-inline-block"
style="user-select: none"
>
<span class="text-primary" aria-hidden="true">#</span>
</router-link>packages/docs/src/components/app/Toc.vue:32
Active table-of-contents entry is marked by color alone
The active TOC list item gets `'text-primary router-link-active'` as its only distinguishing class versus the default `text-medium-emphasis` styling on every other entry. There's no weight, icon, or underline change alongside the color shift.
Why it matters
Colorblind users scanning the table of contents can't tell which section is currently active, since the only signal is a color difference between two otherwise identically styled list items.
Fix
Pair any color-only state indicator with a second non-color cue such as font weight or an icon so the state is visible without color perception.
'text-primary router-link-active': activeItem === to.slice(1),'text-primary router-link-active font-weight-bold': activeItem === to.slice(1),packages/docs/src/components/app/Heading.vue:61
Anchor link has no visible focus state for keyboard users
The `.v-heading > a` rule sets opacity: 0 for `&:not(:hover):not(:focus)`, meaning the link only becomes visible on hover or focus, but no distinct focus style (outline, background, underline) is defined beyond the opacity toggle. A keyboard user tabbing through the page sees the link pop into view with zero visual differentiation from its resting state, no outline to confirm where focus landed.
Why it matters
Without a clear focus indicator, keyboard users lose track of which element is active as they tab through headings, making it hard to confirm the anchor link is focused before pressing Enter.
Fix
Pair any focus-triggered visibility change with an explicit focus-visible outline so keyboard focus location is always unambiguous.
&:not(:hover):not(:focus)
opacity: 0&:not(:hover):not(:focus)
opacity: 0
&:focus-visible
opacity: 1
outline: 2px solid currentColor
outline-offset: 2pxSpacing
packages/docs/src/components/app/Toc.vue:30
Table-of-contents links have a hit target well under 44px
Each TOC entry (`a.v-toc-link`) sits inside an `li` styled with `py-1` (4px top/bottom padding) around `text-body-medium` text, yielding a tap target that's roughly 20-24px tall total.
Why it matters
On mobile, tapping between adjacent TOC entries becomes error-prone when the vertical padding leaves a target well below the ~44px minimum recommended for reliable touch accuracy.
Fix
Give list-based navigation links enough vertical padding to reach a comfortable touch target, even when the visible text stays small.
'ps-3 text-medium-emphasis text-body-medium py-1 font-weight-regular','ps-3 text-medium-emphasis text-body-medium py-2 font-weight-regular',Typography
Color
Components
Motion
UX
Craft
Working well
- Skipping the contents of `link_close`/`link_open` pairs before autolinking commit hashes and issue numbers is a careful touch: it prevents the regex from mangling text that's already inside a hand-authored markdown link.
- The IntersectionObserver-driven active TOC tracking with a stack (activeStack) correctly handles overlapping sections scrolling in/out, which is a subtle scroll-sync detail most implementations get wrong.
- Deriving the tag and classes from props.level via a HEADING_CLASSES map keeps heading semantics (h1-h5) correctly decoupled from visual size, which is the right pattern for accessible heading structure.
- The icon placement logic correctly mirrors context: a leading pound icon for same-page anchors and a trailing external/next-page icon otherwise, using computed props rather than duplicated markup.
Scored August 1, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored July 29, 2026: 59/100. This rescore on v0.0.3: 59/100.
This page is an automated design review of vuetifyjs/vuetify’s UI code: 30 files read against 291 versioned rules covering accessibility, color, typography, spacing, components, UX, motion, and craft. The score is out of 100; confirmed criticals cap it — one at 59, two at 49, three or more at 39.
More design scores
Score your own repo.
Free on public repos, no account. The same engine that scored this page reads your UI code and mints a score page like this one.
Public repos only. The full engine reviews the UI code and mints a public score page — we email you the link too. Already-scored repos open instantly.