← Design styles

Brutalism

Thick strokes, hard offset shadows, flat fills and loud type.

Rendered in designStyle("brutalism"). Atlas terms: DS015, DS016.

Where it comes from

The name was borrowed from architecture, where raw, exposed structure was left visible instead of being finished over. On the web it began as a reaction to interfaces that had become uniformly smooth: rounded, soft, gradient-filled and nearly interchangeable. Early sites in this spirit used default fonts, visible grids and harsh contrast on purpose.

The version used in product interfaces today is gentler and more systematic. It keeps the visible structure (heavy outlines, flat saturated fills, a shadow that is a solid offset block rather than a blur) and drops the hostility. It is loud on purpose, which makes it memorable and also tiring: it works as an accent for a brand moment far better than as the surface of a long working session.

Written by us, in our own words, as background. It is not a claim about users.

Traits

Type

Heavy, uppercase headings at weight 900 in a system sans-serif, tight tracking, bold labels. Type is a graphic element, not a quiet carrier.

--ca-font-weight-heading --ca-heading-case --ca-heading-tracking --ca-label-case --ca-label-tracking

Colour

Flat, saturated fills against a black stroke. No gradients, no tints. The brand colour is used at full strength, which is why contrast has to be checked per preset.

--ca-brand-fill --ca-brand-contrast --ca-border-color

Shape

Square corners and a three to four pixel outline on every surface and control. Icons are drawn with a heavier stroke to match.

--ca-radius-scale --ca-border-width --ca-border-width-strong --ca-icon-stroke

Depth

A hard offset shadow: a solid copy of the border colour pushed down and to the right, with no blur. Bigger surfaces cast a bigger offset.

--ca-shadow-sm --ca-shadow-md --ca-shadow-lg --ca-mat-regular-shadow

Motion

Fast and stepped: half the default duration with a stepped curve, so a state change snaps instead of gliding.

--ca-motion-scale --ca-ease-standard

Before and after, on real components

The same components twice: with the package default and with this style. Use the toggle to flip between them or put them side by side.

Same components, same markup. Only the tokens change.

designStyle("brutalism")
Active Pending Overdue

Weekly report

Revenue grew in three of four regions. The fourth is waiting on a late import.

As on your ID.

Do and don't

Do

  • Keep one outline weight and one shadow offset per elevation, and repeat them everywhere.
  • Use the loud treatment on a few things and leave the rest plain, so the loud parts still read as loud.
  • Check the text colour on every saturated fill; the brand colour has to carry its label.
  • Keep real hierarchy and real navigation under the shouting: order, spacing and clear labels.

Don't

  • Do not use it for the whole of a long form or a dense table; the heavy lines add up to noise.
  • Do not use the shadow offset as the only way to show a pressed or selected state.
  • Do not combine it with blur, gradients or soft tints; that is a different style.
  • Do not set long paragraphs in uppercase or at heading weight.

These are our own guidance for using the recipe well. The accessibility items below carry their sources.

Accessibility pitfalls

Each item names what goes wrong, what the library already does about it and what is left to you.

Saturated fills with white or black text can miss the contrast ratio

Standard or guidelineW3C Web Accessibility Initiative 2023

A bright yellow or pure green fill looks right in a mock-up and can fail the text contrast requirement with a white label.

Scope: WCAG 2.2 Quick Reference, contrast criteria: text needs at least 4.5:1 (3:1 for large text) against its background at level AA. It states what content must do, not what users prefer.

What to do. Take the label colour from `--ca-brand-contrast`, which the preset derives from the fill, and run the preset contrast check when you change the brand colour.

Constant strong stimulation is tiring in long sessions

Our judgement

Heavy outlines on every control raise the visual weight of the whole screen. We have not found a source that measures fatigue for this style, so treat it as a judgement and test it with the people who use the product all day.

What to do. Confine the style to marketing surfaces, empty states and accents; use a calmer recipe for the working screens of the same product.

A hard shadow can be the only cue for a pressed button

Standard or guidelineW3C WAI 2023

State changes carried only by an offset that moves a few pixels are easy to miss, and are not a reliable signal on their own.

Scope: WCAG 2.2 criterion 1.4.11: a visual cue that is needed to identify a control or its state needs 3:1 against its surroundings. A shifted shadow is a cue only if it meets that.

What to do. Also change the fill or the label on press and keep a visible focus ring; the components do both.

Components that fit

Creator tools, campaigns, portfolios, onboarding and landing moments where being remembered matters more than long-session comfort.

Avoid it when: Dense data entry, finance and health screens, and any product used for hours a day.

Where it fits is our judgement from using the recipe, not a measured result.

  • Button: A flat fill, a heavy stroke and a hard shadow define the style.
  • Card: A thick-bordered tile with an offset shadow.
  • Badge: Small saturated labels.
  • Alert: A bold banner that cannot be missed.

Button

Card

Field notes

A card is a surface with a title and room to breathe.

Badge

New Active Pending Overdue

Alert

Overlays such as Dialog and Tooltip render in the page body, outside this style's subtree, so they are not shown here. Apply the style to the whole site to see them wear it.

The ThemeOptions recipe

One call in src/lib/theme.ts. Everything below is what the recipe sets; override any of it on top.

ts
import { designStyle, type ThemeOptions } from "@codeatlasdev/ui";

export const theme: ThemeOptions = designStyle("brutalism");

With your own brand colour on top:

ts
import { designStyle, type ThemeOptions } from "@codeatlasdev/ui";

export const theme: ThemeOptions = designStyle("brutalism", {
	presets: [{ id: "acme", color: "#ff5c00" }],
	defaultPreset: "acme",
});
Every knob this recipe sets
json
{
	"defaultStyle": "outlined",
	"radius": 0,
	"elevation": "hard",
	"border": {
		"width": 3,
		"strong": 4
	},
	"fonts": {
		"body": "system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif",
		"display": "system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif"
	},
	"typography": {
		"weights": {
			"heading": 900,
			"bold": 800,
			"semibold": 700,
			"medium": 600
		},
		"headingTracking": "-0.01em",
		"headingCase": "uppercase",
		"labelCase": "uppercase",
		"labelTracking": "0.04em"
	},
	"motion": {
		"scale": 0.5,
		"easing": "steps"
	},
	"iconStroke": 2.5
}

Try it on this site

Try it on every page of this site, only in this browser. Nothing is published or changed for anyone else.

Prompt for your AI

Paste this into a coding agent. It carries the recipe, the limits and the accessibility rules.

markdown
Build this interface in the "Brutalism" style with @codeatlasdev/ui: Thick strokes, hard offset shadows, flat fills and loud type.

1. In src/lib/theme.ts export `theme = designStyle("brutalism")` (import it from "@codeatlasdev/ui", or from "@codeatlasdev/ui/vite" in a file shared with vite.config). Add your brand as a preset on top: `designStyle("brutalism", { presets: [{ id: "brand", color: "#…" }], defaultPreset: "brand" })`.
2. Use the library components as they are. Change the look only through ThemeOptions or `--ca-*` tokens: no `!important`, no overrides of `.ca-*` classes, no hard-coded colours.
3. The style's traits: type: Heavy, uppercase headings at weight 900 in a system sans-serif, tight tracking, bold labels. Type is a graphic element, not a quiet carrier. Shape: Square corners and a three to four pixel outline on every surface and control. Icons are drawn with a heavier stroke to match. Depth: A hard offset shadow: a solid copy of the border colour pushed down and to the right, with no blur. Bigger surfaces cast a bigger offset. Motion: Fast and stepped: half the default duration with a stepped curve, so a state change snaps instead of gliding.
4. Do: Keep one outline weight and one shadow offset per elevation, and repeat them everywhere. Use the loud treatment on a few things and leave the rest plain, so the loud parts still read as loud. Check the text colour on every saturated fill; the brand colour has to carry its label. Keep real hierarchy and real navigation under the shouting: order, spacing and clear labels.
5. Do not: Do not use it for the whole of a long form or a dense table; the heavy lines add up to noise. Do not use the shadow offset as the only way to show a pressed or selected state. Do not combine it with blur, gradients or soft tints; that is a different style. Do not set long paragraphs in uppercase or at heading weight.
6. Accessibility, which this style puts at risk: Saturated fills with white or black text can miss the contrast ratio. Take the label colour from `--ca-brand-contrast`, which the preset derives from the fill, and run the preset contrast check when you change the brand colour. Constant strong stimulation is tiring in long sessions. Confine the style to marketing surfaces, empty states and accents; use a calmer recipe for the working screens of the same product. A hard shadow can be the only cue for a pressed button. Also change the fill or the label on press and keep a visible focus ring; the components do both.
7. Fits: Creator tools, campaigns, portfolios, onboarding and landing moments where being remembered matters more than long-session comfort. Avoid it when: Dense data entry, finance and health screens, and any product used for hours a day.
8. Keep content, hierarchy and behaviour identical to a plain baseline so the two can be compared. Do not claim the style performs better; validate it with your users.
Docs: https://ui.codeatlas.com.br/styles/brutalism/

References

  1. W3C Web Accessibility Initiative (2023). WCAG 2.2: How to Meet WCAG (Quick Reference). W3C Recommendation.Standard or guideline

    Supports: What conformant content must do, as testable success criteria with a level (A, AA, AAA): for example 1.4.10 Reflow (no two-dimensional scrolling at a width equivalent to 320 CSS pixels, except content that needs two-dimensional layout), 2.4.11 Focus Not Obscured (Minimum) and 2.5.8 Target Size (Minimum) (at least 24 by 24 CSS pixels, with listed exceptions).

    Does not support: What users prefer or what performs better. A standard says what is required, not what is popular.

    Checked 2026-10-25.

  2. W3C WAI (2023). Understanding SC 1.4.11: Non-text Contrast. W3C WAI, WCAG 2.2 Understanding (Level AA).Standard or guideline

    Supports: Meaningful visual cues must achieve 3:1 against the background. The document notes authors do not control font smoothing and anti-aliasing, so evaluation uses the colors obtained from the user agent or the markup.

    Does not support: That thin lines are always inadequate. The document does not set a minimum line width.

    Checked 2026-10-25.