Typography
Coreola uses Inter as the primary typeface, paired with a deliberately tight type scale tuned for dense admin UI.
The settings live in src/themes/defaults/options.ts and src/app/settings.ts.
Font family
fontFamily: ['Inter', '"Helvetica Neue"', '-apple-system', 'Arial', 'sans-serif'].join(',')Inter is self-hosted via @fontsource/inter. Bundled for Cyrillic glyph coverage (Ukrainian locale).
The fallback chain is: Inter → Helvetica Neue → system → Arial → sans-serif. This guarantees readable text even if the webfont fails to load.
Base font size
The MUI base font size is 13px, set in src/app/settings.ts:
baseFontSize: 13This propagates through theme.typography.fontSize and the rem(px) helper in src/themes/defaults/helpers.ts:
export function rem(px: number) {
if (!Number(px)) return px;
return `${(1 / 16) * px}rem`;
}The rem() helper converts pixels to rem using the 16-px convention so the math is predictable, regardless of baseFontSize. Use it whenever you write inline font sizes in component overrides.
MUI typography variants
Coreola uses MUI’s default type scale with a handful of tweaks:
h1 – h6
The MUI defaults (in px equivalents):
| Variant | Default font weight | Coreola override |
|---|---|---|
h1 | 300 | — |
h2 | 300 | — |
h3 | 400 | — |
h4 | 400 | — |
h5 | 400 | — |
h6 | 500 → 400 | overridden to 400 for visual density |
subtitle1, subtitle2
subtitle1 is overridden to fontWeight: 400 (default is 400; this is explicit). subtitle2 is untouched.
body1, body2
Untouched. body1 is the default for most text; body2 is the smaller variant used in tables and dense surfaces.
button
button: {
textTransform: 'none',
}Button labels are never uppercased. This is a deliberate departure from Material Design’s default to keep admin labels readable.
caption, overline
Untouched.
When to use which variant
| Variant | Use for |
|---|---|
h1 | Almost never. Reserved for hero areas (auth screens). |
h2 | Major page heading. One per page maximum. |
h3 | Section heading inside a page. |
h4 | Sub-section heading, card title. |
h5 | Rare. Inline emphasis or dialog title. |
h6 | Card sub-title, list group header. |
subtitle1 | Lead paragraph or section intro. |
subtitle2 | Form group label, smaller intro text. |
body1 | Default paragraph text. |
body2 | Table cells, list items, dense descriptions. |
caption | Help text under a form field, timestamps in lists. |
overline | Category labels above a heading. |
button | Applied automatically by Button — do not use directly. |
Component-specific overrides
The following components have type overrides in options.ts:
MuiBreadcrumbs—fontSize: rem(10). Breadcrumbs are intentionally small to stay out of the way.MuiChip—sizeMediumusesrem(14). ThesizeTinyvariant (Coreola-specific) is 18px tall withborderRadius: 9.MuiInputBase— defaultfontSize: rem(14). Inputs are slightly larger thanbody2for hit-target comfort.MuiButton—sizeTiny12px,sizeSmall13px,sizeMedium14px,sizeLarge16px.MuiTableCell— head cells arefontWeight: 500. Body cells use the default.MuiFormHelperText— small/medium/large at 12/13/14 px respectively, with the error variant prefixed by a"↑ "glyph.MuiTooltip—fontSize: 13,fontWeight: 400.
These are the only places where Coreola deviates from MUI defaults at the typography level. Adding more is discouraged.
Font weights in practice
Coreola uses three weights, no more:
- 400 (Regular) — body text, most labels, button text.
- 500 (Medium) — table head cells, alert filled labels, inline emphasis.
- 600+ (Semi/Bold) — used rarely, only where MUI defaults reach for it (e.g., dialog title, snackbar emphasis).
Italic is reserved for direct quotes and field placeholders generated by MUI. Coreola does not use italic for emphasis — use <strong> (which renders 500/600 depending on context) instead.
Reading the type scale at runtime
To inspect the active type scale from anywhere in the running app:
import { useTheme } from '@mui/material/styles';
const theme = useTheme();
console.log(theme.typography);The theme.typography object includes every variant (h1–h6, body1/body2, etc.) with computed fontSize, lineHeight, letterSpacing, and fontFamily. Useful when debugging spacing problems in dense layouts.
Internationalization considerations
Inter supports Latin and Cyrillic out of the box. The Ukrainian locale (uk) uses the same primary font; Noto Sans is loaded as a Cyrillic-safe fallback in case a glyph is missing.
If you add a locale with a non-Latin script (e.g. Japanese, Arabic), add the corresponding @fontsource/... package and extend the fontFamily array in options.ts.
Anti-patterns
Avoid these — they cause inconsistency and survive code review only by mistake:
- Hard-coded
fontSize: '14px'insx— use a typography variant orrem(14). - Hard-coded font weights — use
theme.typography.fontWeightMedium/fontWeightBold. - Wrapping plain text in custom
styledfor emphasis — use<Typography variant="...">. - Uppercase button labels — Coreola explicitly disables them.
Next steps
- Colors — palette and color roles
- Spacing — the 4-px grid that pairs with the type scale
- Components — components that already honor these rules