Rams MCP · The full engine, now in your coding agent
authgear on GitHub

authgear/authgear-sdk-js

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

17 files reviewed·July 31, 2026

View on GitHub

Elevated

Design risk in this codebase.

7issues
Critical & Serious · top 6 shown below

Top fix

Add a confirmation step before firing Delete Account

See the fix

Verdict

Careful async logic sits next to a delete button with zero confirmation and text nobody can read. The biggest risk is that debug-mode shortcuts, console-only errors, suppressed types, leftover debug copy, have leaked into what reads as production UI.

Files Rams reviewed

example/capacitor/src/pages/Home.css

example/capacitor/src/pages/OAuthRedirect.tsx

example/capacitor/src/pages/ReauthRedirect.tsx

example/capacitor/src/pages/Home.tsx

example/reactnative/src/screens/MainScreen.tsx

example/capacitor/src/App.tsx

example/capacitor/src/theme/variables.css

example/reactnative/src/RadioGroup.tsx

example/reactweb/src/index.tsx

example/capacitor/src/main.tsx

example/reactnative/src/App.tsx

example/reactnative/src/ShowLoading.tsx

example/reactweb/src/App.css

website/src/css/custom.css

example/reactweb/src/App.tsx

example/capacitor/index.html

example/reactweb/index.html

95/100

Accessibility

1 critical1 serious
AccessibilityCritical

example/reactnative/src/screens/MainScreen.tsx:55

Gray description text fails contrast against white background

configureDescText, inputField border, and other text styles in MainScreen.tsx use color: '#888888' on the root view's white background (backgroundColor: 'white'). This gray-on-white pairing computes to 3.5:1 contrast, below the 4.5:1 WCAG AA threshold for normal-sized text (15px).

Why it matters

Users with low vision cannot read the 'Enter Client ID and Endpoint, and then click Configure to initialize SDK' instructions or other description text, which stalls onboarding for anyone relying on that copy.

Fix

Darken secondary text colors to at least #6B6B6B or equivalent to clear 4.5:1 against white.

configureDescText: {
    fontSize: 15,
    color: '#888888',
    marginBottom: 20,
  },
configureDescText: {
    fontSize: 15,
    color: '#595959',
    marginBottom: 20,
  },
AccessibilitySerious

example/reactnative/src/screens/MainScreen.tsx:511

Client ID input has no accessible name for screen readers

The 'Client ID' Text label and the adjacent TextInput (value={clientID}) are connected only through visual proximity in a flex row. There is no accessibilityLabel or accessibilityLabelledBy linking the two, and the same pattern repeats for Endpoint and Authentication Flow Group inputs.

Why it matters

A screen reader user tabbing through the form hears an unlabeled text field with no indication of what to enter, which blocks the configuration flow entirely for that user.

Fix

Add accessibilityLabel to each TextInput matching its visible label text.

<Text style={styles.inputLabel}>Client ID</Text>
          <TextInput
            style={styles.inputField}
            value={clientID}
<Text style={styles.inputLabel}>Client ID</Text>
          <TextInput
            style={styles.inputField}
            accessibilityLabel="Client ID"
            value={clientID}
95/100

UX

1 critical1 serious
UXCritical

example/reactnative/src/screens/MainScreen.tsx:811

Delete Account button fires immediately with zero confirmation

The 'Delete Account' Button (title="Delete Account", onPress={deleteAccount}) sits in a long, unstyled, undifferentiated list of RN Buttons alongside Configure, Login, and other lower-stakes actions, and calls deleteAccount() directly on press with no confirm step.

Why it matters

A single accidental tap in a dense list of identically-styled buttons permanently destroys the account with no way to undo it, which is the highest-cost mistake a user can make on this screen.

Fix

Gate destructive actions behind a confirmation dialog (Alert.alert or similar) before invoking the handler.

<Button
            title="Delete Account"
            onPress={deleteAccount}
            disabled={!initialized || !loggedIn}
          />
<Button
            title="Delete Account"
            onPress={() =>
              Alert.alert(
                'Delete Account',
                'This cannot be undone. Are you sure?',
                [
                  {text: 'Cancel', style: 'cancel'},
                  {text: 'Delete', style: 'destructive', onPress: deleteAccount},
                ],
              )
            }
            disabled={!initialized || !loggedIn}
          />
UXSerious

example/capacitor/src/pages/OAuthRedirect.tsx:23

OAuth failures leave users stuck on a blank screen with no recovery

In finishAuthentication, the catch block only runs console.error(e) with no state update, no error message shown, and no navigation fallback. If configure() or finishAuthentication() throws, the component stays on its loading render forever.

Why it matters

A failed OAuth redirect traps the user on a dead screen with no way back to the app and no explanation of what went wrong, so the only recovery is force-quitting.

Fix

Catch the error into component state and render a retry or back-to-home action instead of only logging it.

} catch (e) {
      console.error(e);
    }
} catch (e) {
      console.error(e);
      setError(e instanceof Error ? e.message : 'Authentication failed');
    }

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
96/100

Craft

2 serious
CraftSerious

example/reactnative/src/App.tsx:15

Type error suppressed instead of fixed on the root safe-area View

The View wrapping MainScreen carries a `{/* @ts-expect-error */}` comment directly above it because safeAreaStyle uses paddingHorizontal: '5%' and paddingVertical: '5%', string values that don't match React Native's expected numeric or DimensionValue padding types.

Why it matters

Suppressing the type error hides a genuine type mismatch, so if the style object grows or the props change shape later, TypeScript can no longer catch a real regression in this file.

Fix

Type safeAreaStyle explicitly as a ViewStyle (or cast the percentage strings) instead of suppressing the checker.

const safeAreaStyle = {
  paddingHorizontal: '5%',
  paddingVertical: '5%',
};

// ...
{/* @ts-expect-error */}
      <View style={safeAreaStyle}>
const safeAreaStyle: ViewStyle = {
  paddingHorizontal: '5%',
  paddingVertical: '5%',
};

// ...
<View style={safeAreaStyle}>
CraftSerious

example/capacitor/src/pages/OAuthRedirect.tsx:34

Debug-only copy ships as the visible message on the redirect screen

The rendered div reads 'Finishing authentication. Open the inspector to see if there is any error.' This is the only message shown to end users on this route, telling a non-technical user to open browser devtools.

Why it matters

Production users who hit an auth error see instructions meant for developers, with no actionable next step, which erodes confidence in the product at the exact moment something already went wrong.

Fix

Replace developer-facing debug copy with a user-facing status message and hide console-only guidance behind an error state.

Finishing authentication. Open the inspector to see if there is any error.
Finishing authentication...

Typography

No issues found

Color

No issues found

Spacing

No issues found

Components

No issues found

Motion

No issues found

Working well

  • Every mutating button (Add Email, Change Phone, Link OAuth, and similar) has its disabled state chained off actual SDK readiness (!initialized, loading, loggedIn, per-feature userInfo checks), which stops users from triggering flows the backend can't yet support. That's the right place to put a guard: at the point of action, not buried in a helper.
  • finishAuthentication in OAuthRedirect.tsx is wrapped in useCallback with router as its only dependency, and the effect depends on that callback rather than re-deriving logic inline. That keeps the effect's dependency array honest and avoids a stale-closure bug on re-render.
  • StatusBar barStyle="light-content" is set explicitly in App.tsx rather than left to the platform default, which keeps the status bar readable against the app's background instead of leaving it to chance per-OS.

Scored July 31, 2026 with Rams Engine v0.0.3 · Engine changelog

This page is an automated design review of authgear/authgear-sdk-js’s UI code: 17 files read against 291 versioned rules covering accessibility, color, typography, spacing, components, UX, motion, and craft. The score is out of 100; any confirmed critical issue caps it at 59.

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