lobehub/lobe-chat
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·August 1, 2026
More findings
Verdict
Solid componentization undercut by sloppy micro-details: jittering digits, clipped text with no recovery, and color-only status dots. The shared primitives are the credit here, but every numeric or truncated surface needs a second pass before this reads as considered.
Files Rams reviewed
src/components/server/MobileNavLayout.tsx
src/app/layout.tsx
packages/builtin-tool-lobe-agent/src/client/components/SortableTodoList/index.tsx
packages/shared-tool-ui/src/components/FileChangeStats/index.tsx
packages/shared-tool-ui/src/components/TodoProgress/index.tsx
src/components/404/index.tsx
src/components/Analytics/index.tsx
src/components/AsyncBoundary/index.tsx
src/components/AsyncError/index.tsx
src/components/AvatarUpload/index.tsx
src/components/BootErrorBoundary/index.tsx
src/components/BrandWatermark/index.tsx
src/components/Cell/index.tsx
src/components/CodeEditorPane/index.tsx
src/components/CollapsibleContent/index.tsx
src/components/CommentList/index.tsx
src/components/CopyableLabel/index.tsx
src/components/DataStyleModal/index.tsx
src/components/Descriptions/index.tsx
src/components/DotsLoading/index.tsx
src/components/DragUploadZone/index.tsx
src/components/Error/index.tsx
src/components/ErrorBoundary/index.tsx
src/components/FileIcon/index.tsx
src/components/FileParsingStatus/index.tsx
src/components/FormAction/index.tsx
src/components/GalleyGrid/index.tsx
src/components/GuideModal/index.tsx
src/components/HighlightNotification/index.tsx
src/components/ImageItem/index.tsx
Typography
packages/shared-tool-ui/src/components/TodoProgress/index.tsx:214
Todo count badge digits shift the header layout as todos complete
The header count badge `{completed}/{total}` in TodoPanelHeader has no tabular-nums applied. As todos complete and the numerator grows (e.g. 9/12 to 10/12), the digit count changes and the badge width shifts against the label text next to it.
Why it matters
Every completed todo nudges the badge and header label horizontally, so the progress indicator feels jumpy exactly when a user is watching it update in real time.
Fix
Apply tabular-nums to the count badge so its width stays fixed as digits change.
<span className={styles.headerCount}>
{completed}/{total}
</span><span className={styles.headerCount} style={{ fontVariantNumeric: 'tabular-nums' }}>
{completed}/{total}
</span>packages/shared-tool-ui/src/components/FileChangeStats/index.tsx:81
Line-stat digits without tabular-nums cause the pill to jitter on update
The `+{linesAdded}` and `-{linesDeleted}` spans in LineStats render plain proportional digits with no `font-variant-numeric: tabular-nums`. As a file's diff stat updates (e.g. +9 to +10), the digit width changes and the pill and anything next to it shifts horizontally.
Why it matters
Live-updating diff stats next to file names cause visible layout shift on every update, making the list feel unstable and harder to scan while a diff is streaming in.
Fix
Apply tabular-nums to numeric stat text so digit width stays fixed regardless of value.
{showAdded && <span className={styles.lineAdded}>+{linesAdded}</span>}
{showDeleted && <span className={styles.lineDeleted}>-{linesDeleted}</span>}{showAdded && <span className={styles.lineAdded} style={{ fontVariantNumeric: 'tabular-nums' }}>+{linesAdded}</span>}
{showDeleted && <span className={styles.lineDeleted} style={{ fontVariantNumeric: 'tabular-nums' }}>-{linesDeleted}</span>}packages/shared-tool-ui/src/components/TodoProgress/index.tsx:225
Truncated step detail in the panel header has no way to recover the full text
The `headerDetail` span rendering `{detail}` in TodoPanelHeader is clamped with ellipsis truncation but carries no `title` attribute. A long step name (e.g. a file path or command) gets clipped with no way to see the rest.
Why it matters
When the step detail is longer than the header width, the user loses the truncated portion entirely, with no hover or tap affordance to recover what task is actually running.
Fix
Add a title attribute mirroring the truncated text so a hover reveals the full string.
<span className={styles.headerDetail}>{detail}</span><span className={styles.headerDetail} title={detail}>{detail}</span>Accessibility
packages/shared-tool-ui/src/components/FileChangeStats/index.tsx:61
Color-only dot leaves file change kind unreadable for colorblind users
KindDot renders a bare `<span className={cx(styles.kindDot, KIND_CLASS[kind], className)} />` with no text, title, or aria-label. Added, deleted, modified, and renamed are distinguished only by the CSS class color applied to an empty span, so the change kind has no non-color signal at all.
Why it matters
A colorblind user or anyone in a low-contrast environment sees an identical gray dot for every file regardless of whether it was added, deleted, modified, or renamed, so they can't tell which files changed how without opening each one.
Fix
Add a title attribute (or aria-label) on the dot that names the change kind so the information survives without color.
export const KindDot = memo<{ className?: string; kind: FileChangeKind }>(({ className, kind }) => (
<span className={cx(styles.kindDot, KIND_CLASS[kind], className)} />
));export const KindDot = memo<{ className?: string; kind: FileChangeKind }>(({ className, kind }) => (
<span className={cx(styles.kindDot, KIND_CLASS[kind], className)} title={kind} aria-label={kind} />
));Color
Spacing
Components
Motion
UX
Craft
Working well
- KindDot and LineStats are extracted once into a shared package instead of being hand-rolled per consumer, which is exactly the right move for repeated visual primitives like diff-stat pills.
- The truncation trio on headerLabel (overflow hidden, white-space nowrap, text-overflow ellipsis) is correctly complete, so the ellipsis actually renders instead of silently failing to clip.
- Using useUnmount to flush pending saves on teardown is a solid guard against data loss when the component leaves the tree mid-debounce.
Scored August 1, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored July 9, 2026: 59/100. This rescore on v0.0.3: 92/100.
This page is an automated design review of lobehub/lobe-chat’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.