Scrim

Updated: Sep 24, 2026
Scrim is a decorative gradient overlay that suppresses part of what is behind it so foreground text and controls stay legible over photos, video frames, or other visually busy material. It owns exactly one thing: the gradient. It does not arrange content, clip anything, size itself, or take focus.
Prefer a scrim that a component already draws. Card has its own, selected with topScrim / bottomScrim and layered with CardAboveScrim and CardBelowScrim. Reach for the standalone component only for a custom media layout. It is not a window background, a panel, or a container material.

Usage

Give the parent a positioning context, drop the scrim in as an overlay, and put the foreground content on a higher stacking level than the scrim.
import { Scrim, ScrimPosition, TextStyle, TextView } from '@wearables-ui-toolkit/mrbd';

export function PhotoCaption({ photo }: { photo: Photo }) {
  return (
    <div className="media-frame">
      <img className="media-image" src={photo.src} alt={photo.alt} />
      <Scrim position={ScrimPosition.BOTTOM} />
      <TextView className="media-caption" textStyle={TextStyle.BODY1}>
        {photo.caption}
      </TextView>
    </div>
  );
}
.media-frame {
  position: relative;
  overflow: hidden;
}

.media-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The scrim is positioned on its own stacking level, so a caption declared
   after it still needs an explicit, higher one to paint above it. */
.media-caption {
  position: absolute;
  right: var(--uit-spacing-large);
  bottom: var(--uit-spacing-large);
  left: var(--uit-spacing-large);
  z-index: 10;
}
style is merged over the computed gradient, so state can drive the scrim directly:
<Scrim position={ScrimPosition.FULL} style={{ opacity: isOverlayOpen ? 1 : 0 }} />

Props

The full prop type is ScrimProps. It extends the standard attributes of a div, so any other DOM attribute you pass is forwarded to the scrim element, and the component forwards its ref there too.
PropTypeDefaultDescription
position
ScrimPosition
ScrimPosition.LEFT
Which gradient the scrim paints.
className
string
''
Class applied to the scrim element. The component ships no class of its own, so this is the only class it carries.
style
CSSProperties
{}
Inline styles merged over the computed positioning and gradient. Anything set here wins.
aria-hidden is always true and cannot be overridden.

Types and enums

ScrimPosition

MemberDescription
LEFT
Opaque at the left edge, fading to transparent at the right. The default.
RIGHT
Opaque at the right edge, fading to transparent at the left.
TOP
Opaque at the top edge, fading to transparent at the bottom.
BOTTOM
Opaque at the bottom edge, fading to transparent at the top.
FULL
A vertical gradient that is partly transparent across the top band, ramps to fully opaque about two thirds of the way down, and stays opaque to the bottom. Use it to suppress a whole background, not to add a light wash.

Behavior

  • Layout. Every position, including the directional ones, absolutely positions the element and fills the parent box. The direction lives in the gradient, not in the element’s size, so the fade always spans the whole parent instead of a fixed-width strip. Give the parent a positioning context, or the scrim resolves against the nearest positioned ancestor instead.
  • Sizing. The scrim has no intrinsic size and contributes nothing to layout. A parent with no height gives it no height.
  • Stacking. The scrim is positioned on its own stacking level, so it paints above the parent’s ordinary in-flow children regardless of DOM order. Foreground content has to be positioned with a higher z-index to sit on top of it.
  • Interaction. Pointer events are disabled, so clicks, presses, and hover pass straight through to whatever is beneath. The scrim is never a focus target and never intercepts one.
  • Color. The gradient is black. On the additive-light display, black emits nothing, so the scrim removes the light of what it covers rather than tinting it. Nothing about the gradient changes with theme.
  • Motion. The component animates nothing by itself. Any fade is something you drive through style or a class of your own.
  • Customization. Because inline styles merge last, opacity, inset, background, and the stacking level can all be overridden per instance without touching the component.
  • Content. The scrim accepts the standard div attributes, so children passed through them do render — but inside an aria-hidden subtree, and with pointer events off. Treat it as an empty element and put content beside it.

Accessibility

  • The element is always aria-hidden="true". It has no role, no accessible name, and no keyboard behavior, so assistive technology never reaches it.
  • It is purely decorative. Everything meaningful must live in a sibling that is visible to assistive technology, above the scrim in stacking order.
  • Give the underlying media real alternative text; the scrim describes nothing.
  • Because pointer events pass through, the scrim never interferes with hit testing or with focus-based directional navigation between real controls.
  • Legibility is still your responsibility. Pick the position that actually covers the foreground text, and check the result against the brightest media the surface can show.
  • Give the scrim’s parent a positioning context and place foreground content above it with an explicit stacking level.
  • Match the position to where the foreground content sits: BOTTOM for a caption anchored to the bottom, LEFT for a leading-edge label.
  • Prefer the scrim Card already draws when the content is a card.
  • Drive appearance and disappearance with style= so the scrim stays in the tree and the transition is yours to control.

Avoid

  • Avoid leaving text or controls beneath the scrim; a static sibling declared after it still paints underneath.
  • Avoid using it as a page background, a panel, or a container material — use Panel or a container material instead.
  • Avoid stacking several scrims to approximate a gradient ScrimPosition does not provide.
  • Keep it non-interactive. It is aria-hidden and ignores pointer events, so it cannot serve as a dismiss target.
  • Avoid nesting foreground content inside it. aria-hidden applies to the whole subtree, so anything you put there disappears from the accessibility tree and cannot be reached by focus navigation.
  • Avoid relying on it to clip or mask media; that belongs to the media container’s own overflow.