triggerdotdev/trigger.dev
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·August 1, 2026
Low
Design risk in this codebase.
More findings
Verdict
Magic numbers are doing the job tokens should: 260px sidebars, arbitrary grid splits, and a stray hex color all repeat intent without sharing a source. Fix the token layer once and most of these serious issues collapse together, but the login testimonial flash is the one users will actually notice first.
Files Rams reviewed
apps/webapp/app/components/LoginPageLayout.tsx
apps/webapp/app/components/layout/AppLayout.tsx
apps/webapp/app/components/layout/MetricsLayout.tsx
apps/webapp/app/components/primitives/SettingsLayout.tsx
apps/webapp/app/components/BackgroundWrapper.tsx
apps/webapp/app/components/BulkActionFilterSummary.tsx
apps/webapp/app/components/DefinitionTooltip.tsx
apps/webapp/app/components/DevPresence.tsx
apps/webapp/app/components/ErrorDisplay.tsx
apps/webapp/app/components/FeatureBadges.tsx
apps/webapp/app/components/Feedback.tsx
apps/webapp/app/components/GitHubLoginButton.tsx
apps/webapp/app/components/GitMetadata.tsx
apps/webapp/app/components/GlobalShortcuts.tsx
apps/webapp/app/components/ListPagination.tsx
apps/webapp/app/components/LogLevelTooltipInfo.tsx
apps/webapp/app/components/LogoType.tsx
apps/webapp/app/components/MachineLabelCombo.tsx
apps/webapp/app/components/MachineTooltipInfo.tsx
apps/webapp/app/components/RuntimeIcon.tsx
apps/webapp/app/components/SetupCommands.tsx
apps/webapp/app/components/Shortcuts.tsx
apps/webapp/app/components/StaleAssetRecovery.tsx
apps/webapp/app/components/TriggerRotatingLogo.tsx
apps/webapp/app/components/UserProfilePhoto.tsx
apps/webapp/app/components/WarmStarts.tsx
apps/webapp/app/components/admin/FeatureFlagsDialog.tsx
apps/webapp/app/components/admin/FlagControls.tsx
apps/webapp/app/components/admin/backOffice/MaxProjectsSection.tsx
apps/webapp/app/components/admin/backOffice/RateLimitSection.tsx
Spacing
apps/webapp/app/components/LoginPageLayout.tsx:71
Right-panel row split hardcodes an arbitrary grid value with no token
The testimonial panel's outer div uses `grid-rows-[1fr_auto]`, an arbitrary Tailwind value that isn't backed by any named layout token in this file.
Why it matters
As a one-off split used only here, this is low risk today, but it means the fixed proportion between the quote block and the logo strip lives nowhere reusable, so a future split-panel layout elsewhere in the app can't share it.
Fix
Extract the repeated 1fr/auto row split into a named utility or shared class if this pattern appears in more than one layout.
<div className="hidden grid-rows-[1fr_auto] pb-6 lg:grid"><div className="hidden grid-rows-testimonial-split pb-6 lg:grid">apps/webapp/app/components/BackgroundWrapper.tsx:10
Sidebar width of 260px is repeated three times with no shared source
`BackgroundWrapper` repeats the literal `260px` as `w-[260px]`, `left: "260px"`, and `backgroundSize: "260px auto"` across three separate style declarations, with no shared constant tying them together.
Why it matters
Resizing the sidebar background later means finding and editing three separate literals correctly, and missing one produces a visible seam between the background images.
Fix
Extract the repeated sidebar width into a single constant and reference it everywhere it's used.
className="absolute left-0 top-0 hidden w-[260px] bg-contain bg-top-left bg-no-repeat lg:block"
style={{
backgroundImage: `url(${blurredDashboardBackgroundMenuTop})`,
aspectRatio: "auto",
height: "100vh",
backgroundSize: "260px auto",
}}const SIDEBAR_WIDTH = 260;
// ...
className={`absolute left-0 top-0 hidden w-[${SIDEBAR_WIDTH}px] bg-contain bg-top-left bg-no-repeat lg:block`}
style={{
backgroundImage: `url(${blurredDashboardBackgroundMenuTop})`,
aspectRatio: "auto",
height: "100vh",
backgroundSize: `${SIDEBAR_WIDTH}px auto`,
}}Accessibility
apps/webapp/app/components/layout/MetricsLayout.tsx:172
Sidebar resize handle has no visible keyboard focus or keyboard resize path
`MetricsLayoutMain` renders a `ResizableHandle` (`id={`${autosaveId ?? "metrics"}-sidebar-handle`}`) as the only way to resize the main/sidebar split. Nothing in this file shows a focus ring, `tabIndex`, or keyboard arrow-key handling attached to it.
Why it matters
A keyboard-only user has no way to discover this control or resize the panel, locking a whole interaction out for anyone not using a mouse or touch.
Fix
Give the resize handle a visible focus ring and a keyboard-operable resize path (role="separator" with aria-valuenow and arrow-key handling).
<ResizableHandle id={`${autosaveId ?? "metrics"}-sidebar-handle`} /><ResizableHandle
id={`${autosaveId ?? "metrics"}-sidebar-handle`}
className="focus-visible:ring-2 focus-visible:ring-blue-500"
aria-label="Resize sidebar"
/>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 freeColor
apps/webapp/app/components/BackgroundWrapper.tsx:34
Background surface hardcodes #101214 instead of the existing token
The third background layer in `BackgroundWrapper` sets `backgroundColor: "#101214"` inline, while the outer wrapper and other surfaces in this file already use the `bg-background-dimmed` token class.
Why it matters
A theme or dark-mode adjustment made to `bg-background-dimmed` elsewhere never reaches this surface, so the background silently drifts out of sync with the rest of the page.
Fix
Replace hardcoded hex values with the existing background token already used elsewhere in this component.
style={{
left: "260px",
backgroundImage: `url(${blurredDashboardBackgroundTable})`,
width: "100%",
height: "100vh",
backgroundSize: "1200px auto",
backgroundColor: "#101214",
}}className="... bg-background-dimmed"
style={{
left: "260px",
backgroundImage: `url(${blurredDashboardBackgroundTable})`,
width: "100%",
height: "100vh",
backgroundSize: "1200px auto",
}}Components
apps/webapp/app/components/primitives/SettingsLayout.tsx:35
Shared settings column width hardcodes an arbitrary max-width value
`SettingsContainer`, the wrapper used to center content on every settings page, sets `max-w-[37.5rem]` as an inline arbitrary Tailwind value instead of a named scale entry.
Why it matters
Every settings page in the app inherits this single number. Adjusting the settings column width later means finding and editing this one arbitrary literal correctly, with no scale entry to reach for.
Fix
Move the shared settings column width into a named Tailwind scale entry so every settings page updates from one source.
className={cn("max-w-[37.5rem] overflow-visible", className)}className={cn("max-w-settings overflow-visible", className)}UX
apps/webapp/app/components/LoginPageLayout.tsx:47
Testimonial quote flashes from blank to populated on every login load
In LoginPageLayout, `randomQuote` starts as `useState<QuoteType | null>(null)` and only gets set inside a `useEffect` that fires after mount. The Header3 quote block renders `{randomQuote?.quote}` immediately, so on first paint the right panel shows an empty quote mark and blank paragraph before the effect swaps in a real testimonial.
Why it matters
The panel next to the login form visibly jumps from empty to populated on every page load, which reads as an unfinished page at the exact moment a new user is forming their first impression of the product.
Fix
Pick the random quote synchronously with a lazy initializer so no null state is ever rendered.
const [randomQuote, setRandomQuote] = useState<QuoteType | null>(null);
useEffect(() => {
const randomIndex = Math.floor(Math.random() * quotes.length);
setRandomQuote(quotes[randomIndex]);
}, []);const [randomQuote] = useState<QuoteType>(
() => quotes[Math.floor(Math.random() * quotes.length)]
);Typography
Motion
Craft
Working well
- The doc comment explicitly states slots bake all chrome and no className is exposed except the two documented escape hatches, which is a real guardrail against spacing drift across pages.
- Splitting the login form and testimonial panel into a 2-column grid that collapses to single-column on mobile (grid-cols-1 lg:grid-cols-2) is a clean, minimal-CSS responsive pattern.
- SettingsRowTitle correctly renders a <label> when htmlFor is passed and a <span> otherwise, keeping semantic form association without forcing callers to choose.
- Using assertNever(typedKey) in the filter switch guarantees every new filter key is handled at compile time, preventing silent gaps as the filter schema grows.
Scored August 1, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored July 9, 2026: 94/100. This rescore on v0.0.3: 88/100.
This page is an automated design review of triggerdotdev/trigger.dev’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.