skeletonlabs/skeleton
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·August 1, 2026
Elevated
Design risk in this codebase.
More findings
Verdict
Icon-only controls define the look here, and none of them announce themselves to assistive tech. The pattern repeats across app bar, panel, and upload examples, so fixing accessible names once and reusing it is the highest-leverage move available.
Files Rams reviewed
playgrounds/skeleton-react/app/components/steps/page.tsx
playgrounds/skeleton-react/src/routes/components/app-bar/index.tsx
playgrounds/skeleton-react/src/routes/components/carousel/index.tsx
playgrounds/skeleton-react/src/routes/components/combobox/index.tsx
playgrounds/skeleton-react/src/routes/components/date-picker/index.tsx
playgrounds/skeleton-react/src/routes/components/file-upload/index.tsx
playgrounds/skeleton-react/src/routes/components/floating-panel/index.tsx
playgrounds/skeleton-react/src/routes/components/listbox/index.tsx
playgrounds/skeleton-react/src/routes/components/marquee/index.tsx
playgrounds/skeleton-react/src/routes/components/menu/index.tsx
playgrounds/skeleton-react/src/routes/components/navigation/index.tsx
playgrounds/skeleton-react/src/routes/components/progress-linear/index.tsx
playgrounds/skeleton-react/src/routes/components/segmented-control/index.tsx
playgrounds/skeleton-react/src/routes/components/toast/index.tsx
playgrounds/skeleton-react/src/routes/components/tree-view/index.tsx
sites/skeleton.dev/src/components/examples/framework-components/popover/react/z-index.tsx
sites/skeleton.dev/src/components/examples/integrations/code-block/react/page.tsx
packages/skeleton-common/src/components/carousel.css
packages/skeleton-common/src/components/combobox.css
packages/skeleton-common/src/components/date-picker.css
packages/skeleton-common/src/components/file-upload.css
packages/skeleton-common/src/components/floating-panel.css
packages/skeleton-common/src/components/listbox.css
packages/skeleton-common/src/components/marquee.css
packages/skeleton-common/src/components/navigation.css
packages/skeleton-common/src/components/progress.css
packages/skeleton-common/src/components/segmented-control.css
packages/skeleton-common/src/components/steps.css
packages/skeleton-common/src/components/switch.css
packages/skeleton-common/src/components/tabs.css
Accessibility
playgrounds/skeleton-react/src/routes/components/app-bar/index.tsx:25
Icon-only app bar buttons announce nothing to screen readers
The menu button in `AppBar.Lead` and the search, calendar, and profile buttons in `AppBar.Trail` are all icon-only (`<MenuIcon />`, `<SearchIcon />`, `<CalendarIcon />`, `<CircleUserIcon />`) with no `aria-label` or visible text. A screen reader reaches four buttons in the toolbar with nothing to announce.
Why it matters
Screen reader users can't tell what any of these four controls do, so the entire app bar becomes unusable without sight.
Fix
Add an aria-label describing each icon button's action.
<button type="button" className="btn-icon btn-icon-lg hover:preset-tonal">
<MenuIcon />
</button><button type="button" aria-label="Open menu" className="btn-icon btn-icon-lg hover:preset-tonal">
<MenuIcon />
</button>playgrounds/skeleton-react/src/routes/components/floating-panel/index.tsx:21
Panel control buttons have no accessible name for minimize, maximize, or close
`FloatingPanel.StageTrigger` (minimized, maximized, default) and `FloatingPanel.CloseTrigger` each render a bare icon (`MinusIcon`, `MaximizeIcon`, `MinimizeIcon`, `XIcon`) with no `aria-label`.
Why it matters
A keyboard or screen reader user opens the floating panel but has no way to identify which of the four header buttons closes it versus resizes it, so managing the panel becomes guesswork or impossible.
Fix
Add an aria-label to every stage and close trigger stating its action.
<FloatingPanel.StageTrigger stage="minimized">
<MinusIcon className="size-4" />
</FloatingPanel.StageTrigger><FloatingPanel.StageTrigger stage="minimized" aria-label="Minimize panel">
<MinusIcon className="size-4" />
</FloatingPanel.StageTrigger>playgrounds/skeleton-react/src/routes/components/file-upload/index.tsx:26
Delete button on uploaded files has no accessible name
`FileUpload.ItemDeleteTrigger` wraps only `<CircleXIcon />` with no `aria-label`, so the delete action for each uploaded file has no text alternative.
Why it matters
A screen reader user hears an unnamed button next to every file entry, so removing a specific file requires trial and error instead of a direct action.
Fix
Add an aria-label naming the delete action, ideally including the file name for context.
<FileUpload.ItemDeleteTrigger>
<CircleXIcon />
</FileUpload.ItemDeleteTrigger><FileUpload.ItemDeleteTrigger aria-label={`Remove ${file.name}`}>
<CircleXIcon />
</FileUpload.ItemDeleteTrigger>Typography
playgrounds/skeleton-react/src/routes/components/file-upload/index.tsx:25
Raw byte count makes file size unreadable at a glance
`FileUpload.ItemSizeText` renders `{file.size} bytes` directly, so a 2MB file shows as "2097152 bytes" instead of a human-readable unit.
Why it matters
Users scanning a file list can't compare sizes at a glance and have to mentally parse large digit strings, which slows down file management decisions.
Fix
Format byte counts into KB/MB/GB with a shared formatter before rendering.
<FileUpload.ItemSizeText>{file.size} bytes</FileUpload.ItemSizeText><FileUpload.ItemSizeText>{formatBytes(file.size)}</FileUpload.ItemSizeText>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 freeSpacing
playgrounds/skeleton-react/src/routes/components/app-bar/index.tsx:24
Toolbar grid template hand-typed as an arbitrary value with no shared source
`AppBar.Toolbar` uses `className="grid-cols-[auto_1fr_auto]"` as a raw arbitrary Tailwind value. The same three-column pattern repeats across the default, centered, and other app bar variants in this file with no shared constant.
Why it matters
Because the grid definition is retyped instead of shared, one variant can silently drift to a different column layout during an edit and nobody notices until the header misaligns.
Fix
Extract the repeated grid template into a single named constant or utility class shared by all app bar variants.
<AppBar.Toolbar className="grid-cols-[auto_1fr_auto]">const TOOLBAR_GRID = 'grid-cols-[auto_1fr_auto]';
// ...
<AppBar.Toolbar className={TOOLBAR_GRID}>Color
Components
Motion
UX
Craft
Working well
- FileUpload uses the compound component pattern with a Context render-prop (`fileUpload.acceptedFiles.map`) to render each item, keeping file list logic declarative and letting the primitive own state instead of hand-rolling it.
- The Control cluster in the floating panel groups minimize, maximize, restore, and close triggers together in the header, matching the familiar window-chrome convention users already know from OS windows.
- All three app bar variants reuse the same `btn-icon`/`btn-icon-lg` utility classes for their icon buttons, keeping the icon button sizing and hover treatment visually consistent across examples.
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 skeletonlabs/skeleton’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.