hatchet-dev on GitHub

hatchet-dev/hatchet

Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.

30 files reviewed·July 25, 2026

View on GitHub

Elevated

Design risk in this codebase.

8issues
Critical, Serious & Moderate · top 6 shown below

Top fix

Add an accessible name to the SSO email field

See the fix

Verdict

Solid form scaffolding undercut by sloppy edge details: an unlabeled SSO field, silent validation errors, and a broken back button that never applies its own class. The any-typed toggle setter is the most telling flaw, a compiler-hidden bug sitting quietly in a flow that otherwise looks careful.

Files Rams reviewed

frontend/app/src/pages/auth/components/auth-layout.tsx

frontend/app/src/pages/auth/components/auth-page.tsx

frontend/app/src/pages/error/components/layout.tsx

frontend/app/src/pages/auth/components/social-auth.tsx

frontend/app/src/pages/auth/login/components/user-login-form.tsx

frontend/app/src/pages/auth/register/components/user-register-form.tsx

frontend/app/src/pages/error/components/generic-error.tsx

frontend/app/src/pages/error/components/new-version-available.tsx

frontend/app/src/pages/error/components/not-found.tsx

frontend/app/src/pages/error/components/resource-not-found.tsx

frontend/app/src/pages/error/components/tenant-forbidden.tsx

frontend/app/src/pages/main/info/components/version-info.tsx

frontend/app/src/pages/main/v1/events/components/additional-metadata.tsx

frontend/app/src/pages/main/v1/events/components/event-columns.tsx

frontend/app/src/pages/main/v1/filters/components/filter-columns.tsx

frontend/app/src/pages/main/v1/filters/components/filter-create-form.tsx

frontend/app/src/pages/main/v1/filters/components/filter-detail-view.tsx

frontend/app/src/pages/main/v1/logs/components/logs-chart.tsx

frontend/app/src/pages/main/v1/managed-workers/$managed-worker/components/github-button.tsx

frontend/app/src/pages/main/v1/managed-workers/$managed-worker/components/managed-worker-activity.tsx

frontend/app/src/pages/main/v1/managed-workers/$managed-worker/components/managed-worker-build-logs.tsx

frontend/app/src/pages/main/v1/managed-workers/$managed-worker/components/managed-worker-build.tsx

frontend/app/src/pages/main/v1/managed-workers/$managed-worker/components/managed-worker-iac-logs.tsx

frontend/app/src/pages/main/v1/managed-workers/$managed-worker/components/managed-worker-instances-table.tsx

frontend/app/src/pages/main/v1/managed-workers/$managed-worker/components/managed-worker-logs.tsx

frontend/app/src/pages/main/v1/managed-workers/$managed-worker/components/managed-worker-metrics.tsx

frontend/app/src/pages/main/v1/managed-workers/components/billing-required.tsx

frontend/app/src/pages/main/v1/managed-workers/components/managed-workers-gate.tsx

frontend/app/src/pages/main/v1/managed-workers/components/managed-workers-table.tsx

frontend/app/src/pages/main/v1/managed-workers/components/monthly-usage-card.tsx

95/100

Accessibility

1 critical1 serious
AccessibilityCritical

frontend/app/src/pages/auth/components/social-auth.tsx:79

SSO email field has no accessible name, only a placeholder

In social-auth.tsx, when the SSO panel expands, the email `<input placeholder="Enter your email">` at line 79 has no `<label>`, `aria-label`, or `aria-labelledby`. Placeholder text disappears once the user starts typing and is never exposed as an accessible name to assistive tech, so a screen reader announces this field as unlabeled.

Why it matters

Screen reader users landing on this input hear only 'edit text' with no indication it wants an email address, so they either skip it or have to guess, blocking SSO sign-in for that group entirely.

Fix

Give every text input a programmatic label via aria-label or a visually-associated <label> element.

<input
  type="text"
  value={email}
  onChange={(e) => setEmail(e.target.value)}
  placeholder="Enter your email"
  className="h-10 flex-1 rounded-md border border-muted-foreground/20 bg-background px-3 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
/>
<input
  type="email"
  value={email}
  onChange={(e) => setEmail(e.target.value)}
  placeholder="Enter your email"
  aria-label="Email address"
  className="h-10 flex-1 rounded-md border border-muted-foreground/20 bg-background px-3 text-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring"
/>
AccessibilitySerious

frontend/app/src/pages/auth/register/components/user-register-form.tsx:78

Name field uses an invalid input type that silently falls back to text

The name `<Input>` in user-register-form.tsx (line 74-82) sets `type="name"`, which is not a valid HTML input type. Browsers silently treat it as `type="text"`, so it looks intentional in the code but carries none of the semantics the author likely meant.

Why it matters

Because the type silently degrades instead of erroring, this can sit unnoticed indefinitely; the field just behaves like a generic text box with no functional harm today, but it signals a broader pattern of untyped attributes slipping past review.

Fix

Use a valid HTML input type; plain text fields should be explicit type=text.

type="name"
type="text"
98/100

Color

1 serious
ColorSerious

frontend/app/src/pages/auth/register/components/user-register-form.tsx:82

Error text color fails AA contrast for small text

The validation messages in user-register-form.tsx use `text-sm text-red-500` (line 82 and its two siblings). Tailwind's red-500 (#ef4444) against a white card background computes to roughly 3.8:1, below the 4.5:1 threshold WCAG AA requires for text at this size.

Why it matters

Users with low vision or in bright-light conditions strain to read exactly the messages that tell them their signup failed, at the worst possible moment: right after a rejected submission.

Fix

Raise error text to a darker red shade that clears 4.5:1 contrast against the background, staying within the existing red hue.

className="text-sm text-red-500"
className="text-sm text-red-600"

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 free
98/100

Components

1 serious
ComponentsSerious

frontend/app/src/pages/auth/components/social-auth.tsx:118

Back button's left-align class is invalid and never applies

The "Back" button in the SSO panel (line 118) uses `className="h-11 justify-left gap-1 ..."`. Tailwind has no `justify-left` utility, only `justify-start`, so this class does nothing and the button falls back to its default flex alignment.

Why it matters

The arrow icon and "Back" text render centered instead of left-aligned as intended, so the button's internal layout is inconsistent with the rest of the panel and doesn't match what the author clearly meant to ship.

Fix

Use the valid Tailwind utility justify-start for left-aligned flex content.

className="h-11 justify-left gap-1 border-muted-foreground/20 bg-background shadow-sm hover:bg-muted/40"
className="h-11 justify-start gap-1 border-muted-foreground/20 bg-background shadow-sm hover:bg-muted/40"
98/100

UX

1 serious
UXSerious

frontend/app/src/pages/auth/login/components/user-login-form.tsx:78

Login password field has no autocomplete, so password managers can't fill it

In user-login-form.tsx, the password `<Input>` (line 71-77) has `type="password"` but no `autoComplete` attribute, while the email input right above it correctly sets `autoComplete="email"`.

Why it matters

Password managers rely on autoComplete='current-password' to know where to insert a saved credential; without it, users on this sign-in form may have to manually copy their password instead of one-click autofill.

Fix

Add autoComplete=current-password to password inputs on login forms.

<Input
  {...register('password')}
  id="password"
  placeholder="Password"
  type="password"
  disabled={props.isLoading}
/>
<Input
  {...register('password')}
  id="password"
  placeholder="Password"
  type="password"
  autoComplete="current-password"
  disabled={props.isLoading}
/>
98/100

Craft

1 serious
CraftSerious

frontend/app/src/pages/auth/components/social-auth.tsx:52

SSO toggle setter typed as any hides a broken update path from the compiler

`SocialAuthButton` accepts `setSsoExpanded: any` (line 52) instead of `Dispatch<SetStateAction<boolean>>`. It's called with `setSsoExpanded(true)` and `setSsoExpanded(false)` to control the entire SSO expand/collapse panel.

Why it matters

With `any`, a future refactor that changes the setter's shape or passes the wrong value type won't fail the build, so the SSO panel can silently stop opening or closing with no compiler warning to catch it.

Fix

Type state setters with React's Dispatch<SetStateAction<T>> instead of any.

setSsoExpanded: any;
setSsoExpanded: Dispatch<SetStateAction<boolean>>;

Typography

No issues found

Spacing

No issues found

Motion

No issues found

Working well

  • Hiding the decorative gradient panel on mobile with hidden lg:flex and letting the form column go full-width below the breakpoint is the right call: ambient visuals that add nothing functional shouldn't cost layout space or bandwidth on small screens.
  • Both the login and register forms pair every input with a real <Label htmlFor> tied to a matching id ("email", "password", "name"), so the core field labeling is correctly accessible even where placeholder text is also present.
  • The SSO Continue link correctly disables itself when the email field is empty, using tabIndex={-1}, href="#", and preventDefault together rather than just a visual disabled state, so keyboard users can't tab into a dead link.

Scored July 25, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored July 9, 2026: 59/100. This rescore on v0.0.3: 59/100.

This page is an automated design review of hatchet-dev/hatchet’s UI code: 30 files read against 309 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.

Or get a design review on every pull requestInstall Rams