mattermost/mattermost
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
Careful component craftsmanship undercut by two hierarchy leaks: identical icons flatten Callout severity, and an uncapped Hero CTA list can bury the primary action. Fix the icon distinction and cap the CTAs, and this jumps from solid to exemplary.
Files Rams reviewed
webapp/channels/src/components/emoji/emoji_page.tsx
webapp/channels/src/components/error_page/error_page.tsx
docs/site/src/components/AttestationStatus/index.tsx
docs/site/src/components/Callout/index.tsx
docs/site/src/components/CardGrid/index.tsx
docs/site/src/components/DeploymentAvailability/index.tsx
docs/site/src/components/DeploymentOnly/index.tsx
docs/site/src/components/EditionAvailability/index.tsx
docs/site/src/components/Hero/index.tsx
docs/site/src/components/IMEDiagram/index.tsx
docs/site/src/components/MethodLegend/index.tsx
docs/site/src/components/PlanAvailability/index.tsx
docs/site/src/components/UpgradeNotesFilter/index.tsx
webapp/channels/src/components/admin_console/audit_logging/index.tsx
webapp/channels/src/components/admin_console/billing/billing_subscriptions/index.tsx
webapp/channels/src/components/admin_console/billing/plan_details/index.tsx
webapp/channels/src/components/admin_console/feature_discovery/index.tsx
webapp/channels/src/components/admin_console/ip_filtering/edit_section/index.tsx
webapp/channels/src/components/admin_console/ip_filtering/index.tsx
webapp/channels/src/components/admin_console/jobs/index.tsx
webapp/channels/src/components/admin_console/permission_schemes_settings/index.tsx
webapp/channels/src/components/admin_console/permission_schemes_settings/permission_system_scheme_settings/index.tsx
webapp/channels/src/components/admin_console/permission_schemes_settings/permission_team_scheme_settings/index.tsx
webapp/channels/src/components/admin_console/permission_schemes_settings/permissions_scheme_summary/index.tsx
webapp/channels/src/components/admin_console/permission_schemes_settings/permissions_tree/index.tsx
webapp/channels/src/components/admin_console/plugin_management/index.tsx
webapp/channels/src/components/admin_console/system_roles/system_role/add_users_to_role_modal/index.tsx
webapp/channels/src/components/admin_console/system_roles/system_role/index.tsx
webapp/channels/src/components/admin_console/system_roles/system_role/system_role_users/index.tsx
webapp/channels/src/components/admin_console/system_users/revoke_sessions_button/index.tsx
Accessibility
docs/site/src/components/Callout/index.tsx:9
Important and Warning callouts share the identical '!' icon
In COPY, kind="important" and kind="warning" both map to icon: '!'. The bar containing the glyph is aria-hidden, so screen readers rely on the label text and are fine, but sighted users scanning the page can only tell the two severities apart by the background/text color set in CSS for .important vs .warning.
Why it matters
A color-only distinction between two severity levels means users with color vision deficiency see two visually identical badges, so they can't tell a routine note from a warning at a glance.
Fix
Give each severity level a distinct glyph shape, not just a distinct color, so the difference survives without color perception.
important: {label: 'Important', icon: '!'},
warning: {label: 'Warning', icon: '!'},important: {label: 'Important', icon: '!'},
warning: {label: 'Warning', icon: '▲'},UX
docs/site/src/components/Hero/index.tsx:43
Hero renders unlimited CTAs with no cap on competing primary buttons
Hero maps over the full ctas array and applies styles.ctaPrimary to every entry unless cta.variant is explicitly 'ghost'. Nothing in the component caps the array length or forces only one cta to be primary, so a caller passing three CTAs without a variant set gets three identically filled, equally weighted buttons in the hero.
Why it matters
When multiple CTAs share the same filled treatment, the primary action becomes ambiguous and decision time increases at the exact moment the page should be directing the visitor toward one next step.
Fix
Cap the CTA list and force styling so only the first action ever renders as primary, with the rest as ghost.
{ctas.map((cta, i) => (
<Link
key={`${cta.label}-${i}`}
to={cta.to}
className={cta.variant === 'ghost' ? styles.ctaGhost : styles.ctaPrimary}
>{ctas.slice(0, 2).map((cta, i) => (
<Link
key={`${cta.label}-${i}`}
to={cta.to}
className={i === 0 ? styles.ctaPrimary : styles.ctaGhost}
>Typography
Color
Spacing
Components
Motion
Craft
Working well
- EditionAvailability handles both the unknown-tier and missing-prop cases with actionable inline error text (listing the valid tiers, or telling the author the prop is required) instead of rendering blank or crashing, which makes a content author's mistake obvious and fixable right in the doc.
- Callout's decorative icon sits inside an aria-hidden bar while the visible label text (title ?? meta.label) carries the actual kind, so screen reader users get the correct distinction even though the icon glyph itself is hidden from them.
- KNOWN_TIERS is derived from Object.keys(TIER_LABEL) rather than duplicated as a separate list, so a new tier can't be added to the type without also getting a label. That's the right way to kill single-source-of-truth drift.
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: 96/100.
This page is an automated design review of mattermost/mattermost’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.