Get Started

ACSS 4 Iconography

Icons in ACSS 4 are driven by an attribute, not a class. Put data-icon on an svg, i or a and the framework sizes it, colours it and centres it. Everything below is live markup — inspect any icon to see the whole API. Line icons are Iconoir; the duotone set is Phosphor.

The API

One attribute, one scale

[data-icon] sets display, colour, flex-shrink and box-sizing. The .icon--* classes only set --icon-size and --icon-padding, so an icon with no size class renders at the 32px default.

.icon--xs
.icon--s
.icon--m
.icon--l
.icon--xl

Every size class has an attribute twin. .icon--l and data-icon-size="l" are the same rule, so you can size an icon without touching its class list:

data-icon-size="s"
data-icon-size="l"

Caveat found while building this page: --icon-size-2xl is not emitted on this install, so .icon--2xl falls through to the hard 24px fallback and renders smaller than .icon--m. The scale is usable from xs to xl.

Sets

Two families, one contract

Any SVG works — the framework never touches the artwork. These line icons paint with currentColor; the duotone set paints its solid layer with currentColor and its back layer with --icon-duo-color, so one class pairs them as primary over base.

Iconoir — line

1.5px strokes, 24px grid. Colour comes from --icon-color through currentColor.

Phosphor — duotone

Two layers on a 256px grid. .icon-duo sets --icon-color to primary and --icon-duo-color to base.

Lists

Icon lists

.icon-list — or the data-icon-list attribute — turns a plain ul into a flex column and re-sizes every icon inside it to 1em, so the bullets track the text rather than a fixed pixel size. .icon--yes and .icon--no are the only two colour shortcuts ACSS ships.

What the framework handles

  • Sizing, colour and alignment from one attribute
  • Automatic 1em scaling inside any icon list
  • Card-aware defaults with no extra markup
  • Hover states through –icon-color-hover

What stays yours

  • The icon set itself — bring any SVG
  • The artwork, including stroke weight
  • Layout of the block around the list
  • Which items read as yes and which as no

Boxes

Icon boxes

Inside a card the framework takes over: .card :where([data-icon]) re-points --icon-size at --card-icon-size, which this install sets to 68px. That is illustration scale, not interface scale — so .card--icon re-points it once at the m step and every icon in the grid follows. Add .icon--boxed and the glyph sits in a tinted chip instead of floating on the card.

No size class

The icon inherits its size from --card-icon-size. Add a size class and the card still wins, because the two rules tie on specificity and the card framework is emitted later.

Colour follows suit

--card-icon-color sits in front of --icon-color, so a card variant can recolour its icons without reaching into the markup.

Radius too

--card-icon-radius feeds --icon-radius, which only shows once the icon is boxed — the next section.

Chips

Boxed icons

.icon--boxed adds padding, a border, a radius and a background around the glyph, all of them variables. Out of the box it lands on the neutral scale; four variable overrides move it onto the brand scale. .icon--plain is the inverse — it zeroes the box again.

Defaults, untouched:

The same class with --icon-color, --icon-background, --icon-border-color and --icon-radius re-pointed at brand tokens:

Callouts

Callouts with icons

A callout is a card that runs horizontally. .callout carries five declarations — it flips --card-flex-direction, retints --card-background, drops the ring and adds one accent edge that a modifier can re-point. Everything else is the card framework, so it inherits padding, radius, gap and hover for free.

Consolidate, do not duplicate

Because .callout shares more than 80% of its styling with .card, it is a modifier rather than a component. Five lines, not forty.

Recolour through the card

Inside a card .icon--no is dead: .card :where([data-icon]) re-declares --icon-color and wins on source order. The card-level variable is the way in, so .callout--danger sets --card-icon-color instead.

Testimonials

Testimonials with icons

ACSS switches its blockquote framework off inside anything whose class contains -card, so figure.card.testimonial-card hands the box straight back to the card framework — no override, no fight. The only icon work left is the star row: .rating sets --card-icon-size once on the parent instead of a size class on each of the five stars.

The icon layer never fights the artwork. We dropped in a set we already licensed and the sizing, colour and hover states came along for free.

Priya RamanDesign Systems Lead

Switching the whole product from 48 to 40 pixel icons was one variable. That is the part that keeps paying us back.

Tom AlderidgeFront-End Engineer

One contract, any surface

On a dark band the icons need one class, not a new component: .icon-banner re-points --icon-color and --icon-duo-color, and every descendant follows. The row itself is .icon-row with the centred modifier.

Fast

Safe

Composable

Consistent