Watermark

A repeating mark of text or an image drawn over its children, to discourage sharing and trace a leaked screenshot.

Accessibility

Watermark adds no semantics, so the work here is not naming it. It is about what a layer of ink over live text costs the reader underneath.

What it renders

Watermark adds one element inside the wrapped container: a <div> with an inline style and nothing else. No children, no text, no role, no alt, no ARIA.
  • The mark is therefore hidden from assistive technology already, and not because anyone hid it. An empty div with a background image exposes no content to a screen reader, so there is nothing to announce and nothing to suppress. Adding aria-hidden to it would change nothing, and you cannot reach it to add anything anyway: Watermark owns the element and rewrites its attributes.
  • pointer-events: none means it never takes a click, and it carries no tabindex, so it is not in the tab order. Everything under the mark keeps its own focus behavior.
  • The element has no class, drops a hidden attribute and forces visibility: visible, and Watermark puts it back when it is changed. That stops tampering, and it has an accessibility cost: a reader's own user stylesheet cannot turn the mark off either.

The mark sits on top of real text

This is the one contrast problem Watermark creates, and it is not about the mark's own legibility. The mark is a semi-transparent layer over live content, so every piece of text underneath is now being read through it.
  • The default ink is token.colorFill, a faint gray in light mode and a faint white in dark. Body text that already sits close to 4.5:1 against its background loses whatever margin it had wherever a stroke of the mark crosses it.
  • Check contrast with the mark on. A contrast check run on the unmarked component is measuring something the reader never sees.
  • The failure is not uniform: the mark is rotated and tiled, so it crosses some lines and misses others. Worst case is a stroke running along a line of small text, which is why a bigger gap and a quieter alpha beat a bigger fontSize.
  • Small text, thin weights and disabled or secondary ink are the first casualties. If a region has to carry both a mark and dense small print, the mark belongs on a heavier gap with less ink, not on a heavier hand.

High contrast and inverted colors

  • A reader who needs high contrast needs the layer between them and the text to be as light as it can be while still doing its job. The only knob is the alpha in font.color, and turning it up for the feeling of security spends that budget on the readers who have least of it.
  • A reader who inverts colors inverts the mark with the page. Inversion happens outside the component, so a mark tuned by eye in one direction is not the mark they get. Do not assume the tuned result survives it.
  • The mark is a raster image, not styled text, so it does not respond to a reader's font size, a user stylesheet or a browser text setting. Zooming the page scales the background image along with everything else rather than reflowing it.
  • The safest configuration for these readers is the default: pass no font.color, and the default token.colorFill follows each mode. A literal chosen in one mode stays that heavy in the other.

The mark must never carry the information

Whatever the mark says, say it somewhere real as well. This is the rule the rest of this page exists to support.
  • It reaches no screen reader, no braille display and no reading mode, because there is no text in the DOM to reach them with.
  • It does not survive a copy and paste, a text extraction, or a reader who has turned images off.
  • It does not reliably survive printing: browsers leave background graphics out of a print by default, so the printed copy may be unmarked.
  • A classification that exists only in the mark exists for sighted readers only. Put “Confidential draft” in a heading, a Tag or an Alert on the page too. The mark repeats it, but it does not announce it.

Nothing here is focusable or animated

  • There is no keyboard surface to document. The overlay takes no focus, offers no interaction and changes no reading order: the wrapped content keeps its own, unchanged.
  • Nothing animates. The mark is a background-image with no transition and no keyframes, so there is no reduced-motion consideration on this component.
  • The one thing that can move is a redraw: changing content, rotate, gap or the theme replaces the image in one step. A live configurator that redraws on every keystroke flickers under the reader, so debounce the input rather than the component.
  • Watermark sets overflow: hidden on its element. Check that nothing inside the marked region needed to scroll or to overflow visibly, because a clipped control is an inaccessible one.