vercel/turbo
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·July 25, 2026
Low
Design risk in this codebase.
More findings
Verdict
Solid bones, unfinished interior: security and hierarchy fundamentals are right, but every stateful moment (loading, error, retry) is missing. The biggest risk is a dead-end error state with no recovery, paired with scaffold copy that never became real content.
Files Rams reviewed
examples/with-docker/apps/web/src/app/page.tsx
apps/docs/app/[lang]/(home)/components/templates.tsx
apps/docs/app/[lang]/(extra)/[...slug]/page.tsx
apps/docs/app/[lang]/(home)/blog/[...slug]/page.tsx
apps/docs/app/[lang]/(home)/blog/page.tsx
apps/docs/app/[lang]/(home)/page.tsx
apps/docs/app/[lang]/(home)/showcase/page.tsx
apps/docs/app/[lang]/(openapi)/docs/openapi/[[...slug]]/page.tsx
apps/docs/app/[lang]/docs/[[...slug]]/page.tsx
apps/docs/app/[lang]/layout.tsx
examples/basic/apps/docs/app/page.tsx
examples/basic/apps/web/app/page.tsx
examples/kitchen-sink/apps/storefront/src/app/layout.tsx
examples/kitchen-sink/apps/storefront/src/app/page.tsx
examples/non-monorepo/app/page.tsx
examples/with-biome/apps/docs/app/page.tsx
examples/with-biome/apps/web/app/page.tsx
examples/with-changesets/apps/docs/src/app/layout.tsx
examples/with-changesets/apps/docs/src/app/page.tsx
examples/with-docker/apps/web/src/app/layout.tsx
examples/with-microfrontends/apps/docs/app/nested/page.tsx
examples/with-microfrontends/apps/docs/app/page.tsx
examples/with-microfrontends/apps/web/app/page.tsx
examples/with-nestjs/apps/web/app/page.tsx
examples/with-nextjs-elysia/apps/web/src/app/layout.tsx
examples/with-nextjs-elysia/apps/web/src/app/page.tsx
examples/with-npm/apps/docs/app/page.tsx
examples/with-npm/apps/web/app/page.tsx
examples/with-otel/apps/docs/app/page.tsx
examples/with-otel/apps/web/app/page.tsx
UX
examples/with-docker/apps/web/src/app/page.tsx:47
Error state is a dead end with no retry path
After "Unable to fetch response" renders, the only other control on the page is the name `<input>` and the same "Submit" button, but there's no explicit retry affordance tied to the error block itself. The user has to rediscover the form is still usable.
Why it matters
Users who hit a failed request are left staring at an error with no clear next step, increasing abandonment instead of recovery.
Fix
Pair every error state with a visible retry action that re-triggers the failed request.
{error && (
<div>
<h3>Error</h3>
<p>{error}</p>
</div>
)}{error && (
<div role="alert">
<h3>Error</h3>
<p>{error}</p>
<Button onClick={onSubmit}>Retry</Button>
</div>
)}examples/with-docker/apps/web/src/app/page.tsx:50
Submit button gives no feedback while the request is in flight
The `onSubmit` handler awaits `fetch(...)` and `result.json()` but the "Submit" button stays enabled and unchanged the entire time. Nothing in the JSX reflects a pending state.
Why it matters
Without a loading or disabled state, users can click Submit multiple times during a slow request, firing duplicate calls with no indication anything is happening.
Fix
Track a pending/loading state and disable the trigger button until the request resolves.
<Button type="submit">Submit</Button><Button type="submit" disabled={isSubmitting}>{isSubmitting ? "Submitting…" : "Submit"}</Button>Typography
examples/basic/apps/docs/app/page.tsx:95
Text arrow glyph in footer link breaks icon consistency
The footer link "Go to turborepo.dev →" uses a raw "→" character next to an `<Image src="/globe.svg">` icon. The glyph renders at whatever weight and baseline the surrounding font gives it, while the adjacent SVG icon has its own fixed stroke weight.
Why it matters
A text glyph next to a vector icon renders at inconsistent weight and alignment across fonts and platforms, making the footer row look unfinished next to "Examples" which uses a clean icon+label pattern.
Fix
Use an inline SVG arrow icon at a matched stroke weight instead of a text glyph for directional affordances.
Go to turborepo.dev →Go to turborepo.dev <ArrowRightIcon aria-hidden width={12} height={12} />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 freeComponents
examples/basic/apps/docs/app/page.tsx:66
Button override bypasses shared component's own styling API
`<Button appName="docs" className={styles.secondary}>Open alert</Button>` forces the shared Button into secondary styling via a raw className instead of a variant prop, while the two `<a>` CTAs above it use `styles.primary` / `styles.secondary` directly.
Why it matters
Styling a shared component through className overrides instead of its intended prop API means the next place Button gets used can silently diverge in appearance, and Button's internal styles can conflict with the injected class.
Fix
Style shared components through their exposed variant/prop API, not by injecting external classNames.
<Button appName="docs" className={styles.secondary}>
Open alert
</Button><Button appName="docs" variant="secondary">
Open alert
</Button>Craft
examples/basic/apps/web/app/page.tsx:26
Page body is unedited scaffold copy, not real product content
The only body content on the page is the ordered list "Get started by editing `apps/web/app/page.tsx`" and "Save and see your changes instantly.", followed by the default Vercel "Deploy now" / "Read our docs" CTAs.
Why it matters
Shipping the Next.js scaffold text as the page's actual content signals the page was never built out, and any real user landing here gets developer instructions instead of a product experience.
Fix
Replace scaffold placeholder copy with real page content before shipping.
<li>
Get started by editing <code>apps/web/app/page.tsx</code>
</li>
<li>Save and see your changes instantly.</li><li>Real onboarding copy for this product</li>
<li>Actual next step for the user, not the developer</li>Accessibility
Color
Spacing
Motion
Working well
- The "Deploy now" and "Read our docs" CTAs are correctly differentiated: "Deploy now" uses `styles.primary` as a filled action with the Vercel logomark, while "Read our docs" uses `styles.secondary` as a lighter-weight link. That's the right pattern, one clear entry point with a supporting secondary action.
- The Name input is correctly tied to its label via `htmlFor="name"` / `id="name"`, so the field announces properly to assistive tech instead of relying on placeholder text alone.
Scored July 25, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored May 13, 2026: 77/100. This rescore on v0.0.3: 89/100.
This page is an automated design review of vercel/turbo’s UI code: 30 files read against 308 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.