Ribbon

A corner banner that wraps a card, for a label like New or Most popular.

Accessibility

Ribbon is decoration with a word in it. It has no role, no tab stop and no handler, so the questions here are where its text lands in the reading order and whether that text is legible.

What a ribbon renders

A wrapper div, then the children, then the banner: a span with the text and an empty div for the fold. No role, no aria-* and no tabIndex.
  • The label is in the reading order. It is real text in a span, so a screen reader reads it as part of the card. Nothing has to be added for that.
  • It is read last, not first. The banner comes after children, so a screen reader reads the card's title and body and only then “Most popular”, while a sighted reader sees the banner before anything else.
  • So the word has to stand on its own, out of order and next to the card's name. “Beta” after a card called “Workflows” still works. A word that was written to be read first does not.
  • If the order matters, say it inside the card as well and let the ribbon repeat it visually.

Color never carries the label

The ribbon always has text, so color is not the only carrier here as long as text actually says the thing. The failure mode is a label written to lean on the hue.
  • Do not split one word across two hues: a green “Plan” and a red “Plan” are the same label to a reader who cannot tell them apart.
  • The color name is not exposed to assistive tech.
  • emphasis is a visual weight, not a semantic level. A subtle ribbon is announced the same as a default one, so if a distinction matters it belongs in the words.

It is not a control

Ribbon takes no onClick, no tabIndex and no role, because it is a label.
  • Reaching the element through a selector or a ref and attaching a handler produces a control with no keyboard route and no announcement. Nothing warns about it.
  • Put the action in the card, where it can be a real button or link with a name, a focus ring and a tab stop.
  • A focusable node inside text is reachable, but it comes last in the card's tab order and sits in a thin band over the corner. A keyboard reader meets it after everything else, which is the opposite of where it looks.

Contrast

  • At default the fill is the preset's dark shade and the label is colorTextLightSolid. That pair holds across the presets.
  • At subtle the fill, fold and text come from the color ramp. The text reaches at least 3.7:1 in light mode and 5.2:1 in dark mode across the presets.
  • Check subtle text on yellow and gold. Its label misses AA contrast on those hues, so keep the ribbon a marker beside its content, never the only place something is said.
  • Check a custom color yourself. A hex becomes the fill with a light label on top, so a pale one leaves near-white on near-white with no warning.
  • The label is already the smallest text on the card, one step below body text. Do not step it down again.

The fold is decoration

  • The fold is an empty div. It carries no text, so a screen reader skips it and it needs no aria-hidden.
  • At default the fold is a darker shade of the fill. At subtle it takes the next step of the color ramp, so it stays visible against the tint.
  • The fold is decoration only. A surface that clips it loses nothing a reader needs, so check that the word is still fully visible.
  • The ribbon declares no transition of its own, so there is no motion here to gate behind a reduced-motion query.