MediaWrapper

Updated: Sep 24, 2026
Use MediaWrapper when a caption, control row, or media element sits over a bright or unpredictable backdrop. It stacks a darkened content band with a directional gradient, which keeps the content legible while blending the band into the surrounding background.
MediaWrapper owns the band order, gradient, and darkening. The parent owns the material, shape, clipping, focus, and activation because the wrapper is not a surface or interactive control.
import {
  MediaWrapper,
  MediaWrapperPosition,
  MediaWrapperSize,
  TextStyle,
  TextView,
} from '@wearables-ui-toolkit/mrbd';

export function CaptureCaption({ capture }: { capture: Capture }) {
  return (
    <MediaWrapper
      position={MediaWrapperPosition.BOTTOM}
      size={MediaWrapperSize.LARGE}
    >
      <div className="capture-caption">
        <TextView textStyle={TextStyle.BODY2_EMPHASIZED}>{capture.title}</TextView>
        <TextView textStyle={TextStyle.BODY2}>{capture.timestamp}</TextView>
      </div>
    </MediaWrapper>
  );
}
.capture-caption {
  display: grid;
  gap: var(--uit-spacing-small);
  padding: var(--uit-spacing-large);
}
Prefer anchoring the wrapper to the relevant edge of its region and pointing the gradient away from that edge:
import { MediaWrapper, MediaWrapperPosition } from '@wearables-ui-toolkit/mrbd';

<div className="media-frame">
  <img className="media-frame-image" src={photo.src} alt={photo.description} />
  <MediaWrapper
    className="media-frame-header"
    position={MediaWrapperPosition.TOP}
  >
    <HeaderRow />
  </MediaWrapper>
</div>;
.media-frame {
  position: relative;
}

.media-frame-header {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
}
The component and both enums are also available from the component subpath:
import {
  MediaWrapper,
  MediaWrapperPosition,
  MediaWrapperSize,
} from '@wearables-ui-toolkit/foundation/components/MediaWrapper';

Props

The complete prop type is MediaWrapperProps. It extends the standard div attributes. The component spreads every prop not listed below onto the root element and forwards a ref to that root.
PropTypeDefaultDescription
children
ReactNode
—
Content rendered in the darkened band.
size
MediaWrapperSize
MediaWrapperSize.LARGE
Controls the gradient depth and how much remains fully dark before fading.
position
MediaWrapperPosition
MediaWrapperPosition.BOTTOM
Selects the side of the content where the gradient appears.
className
string
''
Class added to the root.
style
CSSProperties
—
Inline styles applied to the root.

Types and enums

MediaWrapperSize
  • SMALL — uses a shallower gradient band that fades across its full depth
  • LARGE — uses a deeper gradient band that keeps the dark tone for part of its depth before fading
MediaWrapperPosition
  • TOP — places content first and the gradient below it, fading downward
  • BOTTOM — places the gradient first, fading downward into the content below it

Behavior

Layout. The root is a full-width column that stretches its children. It always renders two boxes: the content slot and the gradient. position owns their order. TOP places the content before the gradient, while BOTTOM places the gradient before the content. The darkened band and gradient are a single, supported composition and cannot be disabled independently. The wrapper’s height is the gradient depth plus the height its content requires.
Color. The content slot uses a fixed dark overlay. The gradient transitions between that overlay and var(--uit-color-background-flat), which is transparent. Black emits no light on the additive-light display, so the wrapper reduces the light from covered content instead of tinting it. The gradient then blends the band into the content behind it. This treatment does not change with theme.
Size.size controls the gradient band’s depth. SMALL fades across the full depth. LARGE is deeper and keeps the dark tone near the content before fading across the remaining area. The band does not shrink below its configured depth, so the application should reserve enough space. The application also owns content padding and dimensions because neither size changes the content’s intrinsic dimensions.
Interaction. The gradient ignores pointer events, so it does not block content beneath it. The wrapper does not add focus behavior and is not a focus target.
Positioning. The wrapper participates in normal flow. To place it over media, the application provides a positioning context on the media frame and absolutely positions the wrapper, as shown in the second example.

Accessibility

  • MediaWrapper is a layout and visual-treatment wrapper, so it adds no role or accessible name.
  • The gradient is aria-hidden and is not announced.
  • Informative media must have meaningful alternative text. Mark media as decorative only when it conveys no information, so assistive technology receives the same content.
  • Treat the darkened band as a legibility aid, not a contrast guarantee. Check content against the brightest real backdrop it uses to maintain accessible contrast.
  • Use the wrapper where a caption or control row meets full-bleed media or a bright backdrop.
  • Match position to the content’s anchored edge so the gradient fades away from that edge.
  • Prefer spacing tokens for padding inside the content band.
  • Keep clipping, material, shape, and interaction in the parent that owns the surrounding surface.

Avoid

  • Avoid using MediaWrapper as a standalone card, panel, or interactive surface; it does not provide those behaviors.
  • Avoid adding a second scrim when the owning component already provides one, such as a Card with topScrim or bottomScrim.
  • Avoid relying on the wrapper for shape or clipping because it provides neither.
  • Prefer responsive parent layout over fixed viewport dimensions for the content.