Mask Gradient X

Fades its child out at the left and at the right, so a row that scrolls sideways dissolves instead of stopping against an edge.

API

Props

proptypedefault
children?ReactElementthe element to mask; cloned, not wrapped
fade?string"2rem"length of both fades at once
fadeLeft?stringlength of the left fade; overrides fade
fadeRight?stringlength of the right fade; overrides fade
offsetLeft?string"0px"where the left fade starts
offsetRight?string"0px"where the right fade starts, from the end

Examples

Usage

tsx
<MaskGradientX fade="3rem">
  <div className="flex gap-2 overflow-x-auto"></div>
</MaskGradientX>
previewscroll the row sideways
filter 1
filter 2
filter 3
filter 4
filter 5
filter 6
filter 7
filter 8
filter 9
filter 10
filter 11
filter 12
filter 13
filter 14

One side only

A row that starts flush against its container usually wants nothing on the left and a fade on the right, so the first item stays sharp and only the overflow dissolves.

tsx
<MaskGradientX fadeLeft="0px" fadeRight="4rem">
  <div className="flex gap-2 overflow-x-auto"></div>
</MaskGradientX>
previewsharp on the left, fading on the right
filter 1
filter 2
filter 3
filter 4
filter 5
filter 6
filter 7
filter 8
filter 9
filter 10
filter 11
filter 12
filter 13
filter 14

Details

A mask, not an overlay

The fade is a mask-image on the element itself, so the content becomes genuinely transparent instead of being covered by a gradient painted in the background colour. Whatever is behind shows through, in both themes, with no colour to keep in sync.

css
mask-image: linear-gradient(
  to right,
  transparent var(--offset-left),
  #000 calc(var(--offset-left) + var(--fade-left)),
  #000 calc(100% - var(--offset-right) - var(--fade-right)),
  transparent calc(100% - var(--offset-right))
);

As on the vertical axis, the mask applies to the whole element and cannot be undone locally: anything that must stay fully opaque belongs outside the masked element.

Fade and offset

fade is the length over which the content dissolves; offset is where that dissolve begins. Both take any CSS length, custom properties included, so the values can be tokens rather than numbers.

When a horizontal fade is the wrong answer

A row that scrolls sideways is a legitimate pattern — filters, tags, a gallery — and there the fade tells the reader that the row continues. Elsewhere it usually hides an overflow that should have been solved: text that fades at the right edge is text nobody can finish reading, and a table that fades is a table that wanted fewer columns.