Contrast and size
Two display settings can be tuned by the end user or by the consuming project: the contrast level and the size of the interface. Neither needs JavaScript or a component prop.
Contrast
Ooko has a normal mode and a high-contrast mode. High contrast moves every semantic border and text shade two steps toward the strongest one (--o-text-neutral-dark uses shade 700 instead of 500, for example), and turns the default text and background into pure black and white. Dark mode reverses the palette, so the same steps make text and borders brighter there. Background shades, and therefore component fills, keep their normal value.
High contrast turns on in two ways:
- automatically, when the operating system or browser requests it through
prefers-contrast: more; - explicitly, with
data-ooko-contrast="more"onhtmlor on any container.
Any other value on html, such as data-ooko-contrast="normal", keeps the normal mode even when the system requests more contrast. Without the attribute, Ooko follows the system preference. Use the attribute to honor a setting stored by your application:
function setContrast(level: "system" | "more" | "normal"): void {
if (level === "system") document.documentElement.removeAttribute("data-ooko-contrast");
else document.documentElement.setAttribute("data-ooko-contrast", level);
}High contrast only changes semantic tokens, so application styles that consume --o-text-*, --o-border-*, --o-text-color-default, and --o-background-color-default follow it too. It combines with data-ooko-theme; forced-colors mode still takes precedence where components provide system-color fallbacks.
Interface size
The size of the whole interface follows the font-size set on html. Text, spacing, radii, control heights, and icon sizes are all expressed in rem, so they scale together. Ooko never sets a font-size on html; without one, the browser default (usually 16px, adjusted by the user's own browser setting) applies.
Only hairlines stay in pixels: borders, focus outlines, dividers, the visually hidden 1px clip, and the 9999px pill radius. They keep their crisp width at every size.
To let users choose a size, set a percentage on html so their browser preference is kept as the base:
html {
font-size: 100%;
}
html[data-app-size="large"] {
font-size: 112.5%;
}
html[data-app-size="small"] {
font-size: 87.5%;
}Prefer percentages or rem over a fixed px value on html, which would override the user's browser font-size setting.