picocss/pico
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·July 25, 2026
More findings
Verdict
Solid tokens, shaky states: Pico nails static theming but fumbles the dynamic moments where focus and motion actually matter. A closed dropdown that still traps keyboard focus on invisible links is the kind of bug that undercuts an otherwise accessibility-literate codebase.
Files Rams reviewed
scss/components/_accordion.scss
scss/components/_card.scss
scss/components/_dropdown.scss
scss/components/_group.scss
scss/components/_loading.scss
scss/components/_modal.scss
scss/components/_nav.scss
scss/components/_progress.scss
scss/components/_tooltip.scss
scss/_index.scss
scss/_settings.scss
scss/colors/utilities/_background-colors.scss
scss/colors/utilities/_colors.scss
scss/colors/utilities/_css-vars.scss
scss/colors/utilities/_settings.scss
scss/colors/utilities/_utils.scss
scss/content/_button.scss
scss/content/_code.scss
scss/content/_embedded.scss
scss/content/_link.scss
scss/content/_misc.scss
scss/content/_table.scss
scss/content/_typography.scss
scss/forms/_basics.scss
scss/forms/_checkbox-radio-switch.scss
scss/forms/_input-date.scss
scss/forms/_input-file.scss
scss/forms/_input-range.scss
scss/forms/_input-search.scss
scss/helpers/_functions.scss
Accessibility
scss/components/_dropdown.scss:159
Closed dropdown submenu links stay keyboard-focusable while invisible
The submenu selector `details.dropdown > summary + ul` is hidden in its closed state with `opacity: 0` alone, while `display: flex` and `position: absolute` stay active and there is no `visibility` or `pointer-events` change. A keyboard user tabbing through the closed dropdown lands on invisible `a` links inside the hidden `ul`, with no visual indicator of where focus is.
Why it matters
A keyboard-only user tabs into a menu that looks closed but is silently swallowing focus, so they lose track of their position on the page with no visible cue to recover.
Fix
Pair opacity with visibility and pointer-events so the closed submenu is removed from the focus order until it opens.
#{$parent-selector} details.dropdown > summary + ul {
display: flex;
z-index: 99;
position: absolute;
left: 0;
...
opacity: 0;
@if $enable-transitions {
transition:
opacity var(#{$css-var-prefix}transition),
transform 0s ease-in-out 1s;
}#{$parent-selector} details.dropdown > summary + ul {
display: flex;
z-index: 99;
position: absolute;
left: 0;
...
opacity: 0;
visibility: hidden;
pointer-events: none;
@if $enable-transitions {
transition:
opacity var(#{$css-var-prefix}transition),
visibility 0s linear var(#{$css-var-prefix}transition),
transform 0s ease-in-out 1s;
}
}
#{$parent-selector} details[open].dropdown > summary + ul {
opacity: 1;
visibility: visible;
pointer-events: auto;Motion
scss/components/_accordion.scss:18
Accordion summary color transition ignores reduced-motion preference
The `summary` element inside `details` (accordion trigger) applies `transition: color var(#{$css-var-prefix}transition)` guarded only by `$enable-transitions`, a build-time Sass flag, with no runtime `prefers-reduced-motion` media query.
Why it matters
Vestibular-sensitive users who set 'reduce motion' at the OS level still get the animated transition on every accordion toggle, because the guard only exists at compile time, not at the user's runtime preference.
Fix
Wrap transition declarations in @media (prefers-reduced-motion: no-preference) so the OS-level setting is respected at runtime.
summary {
line-height: 1rem;
list-style-type: none;
cursor: pointer;
@if $enable-transitions {
transition: color var(#{$css-var-prefix}transition);
}summary {
line-height: 1rem;
list-style-type: none;
cursor: pointer;
@if $enable-transitions {
@media (prefers-reduced-motion: no-preference) {
transition: color var(#{$css-var-prefix}transition);
}
}Get this score on every PR.
Rams reviews each pull request on your repo and posts inline one-click fixes — about a minute per review.
Install Rams freeCraft
scss/components/_dropdown.scss:161
Dropdown z-index of 99 is a hardcoded magic number
The submenu rule `#{$parent-selector} details.dropdown > summary + ul` sets `z-index: 99` as a literal integer, while every other value in the same ruleset (border, radius, background, box-shadow, color) goes through a `var(#{$css-var-prefix}...)` token. The z-index is the one property that bypasses that layer.
Why it matters
A future modal, toast, or tooltip added at z-index 100+ without knowing about this arbitrary 99 creates unpredictable stacking bugs, and there is no shared scale to check against before picking a new value.
Fix
Route z-index through the same CSS custom property token layer used for every other value in this ruleset.
#{$parent-selector} details.dropdown > summary + ul {
display: flex;
z-index: 99;
position: absolute;#{$parent-selector} details.dropdown > summary + ul {
display: flex;
z-index: var(#{$css-var-prefix}dropdown-z-index, 99);
position: absolute;Typography
Color
Spacing
Components
UX
Working well
- The `:focus-visible` box-shadow pattern (removing the default outline but restoring a visible ring only for keyboard focus, using the `--outline-width` and `--primary-focus` tokens) is the correct way to give keyboard users a clear focus indicator without adding a ring to every mouse click.
- The indeterminate progress bar wraps its looping gradient sweep in `@media (prefers-reduced-motion: no-preference)`, giving reduced-motion users a static bar instead of continuous motion. That's the exact pattern the dropdown and accordion transitions in this review are missing.
- The native `<dialog>` element with `[open]`/`:not([open])` state handling gets focus trapping and top-layer stacking for free, which avoids the bugs that come with a hand-rolled overlay `div` and z-index juggling.
Scored July 25, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored July 14, 2026: 74/100. This rescore on v0.0.3: 59/100.
This page is an automated design review of picocss/pico’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.