Skip to content

Watermark ​

A container-level watermark layer that sits on top of the content without intercepting any interaction, suitable for preventing sensitive information from leaking.

Rendering engine: text and grayscale image watermarks are drawn on a canvas (the tile is tiled via toDataURL as a background), scaled by devicePixelRatio so they stay sharp on high-DPI screens; SSR and canvas-less environments automatically fall back to an SVG data-uri (fill=currentColor follows the theme). Both paths render an identical structure, and true hydration takes over after validating it. Tiles are cached by paint parameters and repainted only when a relevant attribute or the theme color changes; window resize is handled natively by background tiling.

Text Watermark ​

Basic text watermark

The text watermark is tiled; any content inside the container can be passed in as the slot

text generates a diagonally tiled unit; with repeat the unit is tiled, otherwise a single unit is centered.

Single Unit and Opacity ​

Single centered + opacity

opacity controls the transparency of the watermark layer (0–1, automatically clamped to bounds).

Image Watermark ​

Image watermark

The `image` attribute takes an image URL; when both text and image are present, image wins

Image Grayscale ​

grayscale: grayscale image filter

With grayscale, the image watermark is converted to grayscale via canvas filter: grayscale(1) (cross-origin images require CORS headers from the origin, otherwise it falls back to the original image); canvas-less environments fall back to a layer CSS filter, so the capability is never lost.

No Interaction Interception ​

Normal content interaction

The watermark layer has `pointer-events: none`, so interactions with buttons / inputs above are completely unaffected.

Empty Container ​

Watermark shown without content

When the container has no slot content at all, the watermark layer still renders.

Multi-line, Rotate and Font ​

Multi-line text / rotate / font family

text supports a JSON array (or \n) for multiple lines; rotate controls the angle (default -30); font-size / font-weight / font-family are applied to the canvas text; color accepts 11 preset names (resolved to --oas-preset-* tokens, dark-adaptive) or any CSS color value. By default the watermark follows the theme text color (visible in dark mode too, and repainted automatically on theme switch). The first tile intentionally keeps CJK text (["内部资料","CONFIDENTIAL"]) to demonstrate multi-font rendering through the canvas font stack.

Gap and Offset ​

gap / offset tiling parameters

gap="[x,y]" controls the tile spacing (defaults to the tile size) and offset="[x,y]" controls the starting offset (defaults to gap/2); width / height resize the text tile (auto-fit to content when unset: rotated bounding box + padding, so every tile fully contains the text at default density), and z-index raises the watermark layer (default 2).

Staggered Layout ​

staggered odd/even row offset

With staggered, a second background layer offset by half a tile staggers the odd/even rows (repeat mode only).

Tamper Proof ​

tamper-proof: a watermark you cannot simply delete

Open the browser devtools and delete the watermark layer inside the shadow root, or rewrite its style — the watermark re-mounts/restores itself and fires an oas-remove event
Simulate tampering (delete the layer)tamper-proof="false" comparison

No tampering detected yet

tamper-proof is on by default (="false" turns it off): a MutationObserver watches for the watermark layer being removed or its style being rewritten, re-mounts/restores it automatically, and fires an oas-remove event (detail.type is removed / modified). It deters casual removal, not determined attackers — it is not a security boundary.

Movable Watermark ​

movable: drag the watermark

Press and drag on the watermark (grab cursor); the pattern follows the gesture and offset is written back live

With movable, the watermark layer takes over pointer input (grab/grabbing cursor) and writes the drag displacement to the offset attribute — a controlled channel, so the position survives re-renders. Note that in this mode the watermark layer intercepts interactions over the area it covers.

Fullscreen Watermark ​

fullscreen: a watermark covering the whole viewport

Enable fullscreen watermark

Click the button to enable a fullscreen watermark: the host becomes fixed and covers the viewport, stays put while the page scrolls, and intercepts no interaction; click again to turn it off.

With fullscreen, the component itself becomes position: fixed; inset: 0 covering the viewport (pointer-events: none) — no wrapper needed; it defaults to the topmost z-index, adjustable via the z-index attribute or the --oas-watermark-fullscreen-z-index CSS variable. It composes with repeat / staggered / movable / grayscale; without fullscreen, container mode behaves exactly as before. Note: slotted content is not laid out or interactive in fullscreen mode.

API ​

oas-watermark ​

Attributes ​

AttributeDescriptionTypeDefault
colorWatermark text color: 11 preset names (--oas-preset-*) or any CSS color; defaults to the primary text tokenstring—
font-familyFont family (default sans-serif)stringsans-serif
font-sizeFont size in px (default 16)string16
font-weightFont weight (default 400)string400
fullscreenFullscreen watermark: the host becomes fixed inset:0 covering the viewport (pointer-events:none) at the topmost z-index by default (adjustable via the z-index attribute or --oas-watermark-fullscreen-z-index); stays put while scrollingboolean—
gapTiling gap JSON [x,y] (defaults to tile size)string—
grayscaleGrayscale filter for image watermarks (canvas filter: grayscale(1)); falls back to a layer CSS filter without canvasboolean—
heightText tile height (auto-fits content when unset; image default 120)string—
imageImage watermark URL (takes precedence over text when present)string—
movableDraggable watermark (drag delta writes back to the offset attribute)boolean—
offsetTiling start offset in px or JSON [x,y] (default gap/2, visually identical to the old centered mode)string—
opacityWatermark layer transparency (0–1, auto-clamped)string0.15
repeatBoolean; when present the unit is tiled, otherwise a single unit is centeredboolean—
rotateRotation in degrees (default -30)string-30
staggeredStaggered layout (two-layer background, second layer offset by offset + gap/2; tiling mode only)boolean—
tamper-proofTamper protection (default true): a MutationObserver re-mounts the layer when it is removed/modified and fires oas-remove; "false" disables itstringtrue
textText watermark content (either text or image)string—
widthText tile width (auto-fits content when unset: rotated bounding box + padding; image default 240)string—
z-indexWatermark layer z-index (default 2); in fullscreen mode it is written to the host, overriding the default topmost levelstring—

Events ​

EventDescription
oas-removeFired when tamper protection detects the layer being removed/modified, detail: { type: "removed" | "modified" }

Slots ​

NameDescription
defaultContent covered by the watermark

CSS Variables ​

CSS VariableDefault
--oas-watermark-fullscreen-z-index2147483647

The watermark is a decorative layer (aria-hidden + pointer-events: none): it is excluded from the accessibility tree and does not intercept interaction.

Released under the MIT OR Apache-2.0 License.