Skip to main content
import { Overlay, Button } from 'reshaped';

function Example() {
  const [active, setActive] = React.useState(false);

  return (
    <>
      <Button onClick={() => setActive(true)}>Show Overlay</Button>
      
      <Overlay
        active={active}
        onClose={() => setActive(false)}
      >
        <View
          padding={6}
          backgroundColor="neutral"
          borderRadius="medium"
        >
          <Text>Overlay content</Text>
          <Button onClick={() => setActive(false)}>Close</Button>
        </View>
      </Overlay>
    </>
  );
}

Usage

Overlay is a low-level component for creating full-screen overlay containers. It handles portal rendering, animations, click-outside detection, and scroll locking. Use Modal for most dialog use cases.

Props

active
boolean
Controls the visibility of the overlay.
<Overlay active={isOpen} onClose={() => setIsOpen(false)}>
children
React.ReactNode | (props: { active: boolean }) => React.ReactNode
Content of the overlay. Can be a render function that receives the active state.
<Overlay active={active}>
  <View>Content</View>
</Overlay>

<Overlay active={active}>
  {({ active }) => <View opacity={active ? 1 : 0}>Content</View>}
</Overlay>
transparent
boolean | number
Make the overlay background transparent. Pass a number (0-1) for custom opacity.
<Overlay transparent> {/* Fully transparent */}
<Overlay transparent={0.5}> {/* 50% opacity */}
blurred
boolean
Apply blur effect to the overlay background.
<Overlay blurred>
overflow
string
Control overflow behavior of the content.Options: "auto", "hidden"Default: "auto"
onClose
(args: { reason: string }) => void
Callback when the overlay is closed. Reason can be:
  • "overlay-click": User clicked on the overlay background
  • "escape-key": User pressed Escape
<Overlay
  onClose={({ reason }) => {
    console.log('Closed via:', reason);
    setActive(false);
  }}
/>
onOpen
() => void
Callback when the overlay opens.
onAfterOpen
() => void
Callback after the open animation completes.
onAfterClose
() => void
Callback after the close animation completes.
disableCloseOnClick
boolean
Prevent closing when clicking on the overlay background.
<Overlay disableCloseOnClick>
containerRef
React.RefObject<HTMLElement>
Container element to render the overlay within.
const containerRef = React.useRef();

<View attributes={{ ref: containerRef }}>
  <Overlay containerRef={containerRef}>
</View>
contained
boolean
Contain the overlay within the container bounds. Defaults to true when containerRef is provided.
className
string
Additional CSS class for the root element.
attributes
Attributes<'div'>
Additional HTML attributes for the root element.

Examples

Basic Overlay

function BasicOverlay() {
  const [active, setActive] = React.useState(false);

  return (
    <>
      <Button onClick={() => setActive(true)}>Open</Button>
      
      <Overlay active={active} onClose={() => setActive(false)}>
        <View
          align="center"
          justify="center"
          height="100%"
          onClick={() => setActive(false)}
        >
          <View
            padding={6}
            backgroundColor="neutral"
            borderRadius="medium"
            onClick={(e) => e.stopPropagation()}
          >
            <Text variant="title-5">Overlay Content</Text>
            <Button onClick={() => setActive(false)}>Close</Button>
          </View>
        </View>
      </Overlay>
    </>
  );
}

Transparent Overlay

<Overlay transparent active={active} onClose={handleClose}>
  <View align="center" justify="center" height="100%">
    <View padding={6} backgroundColor="neutral" borderRadius="medium">
      <Text>Content on transparent overlay</Text>
    </View>
  </View>
</Overlay>

Blurred Overlay

<Overlay blurred active={active} onClose={handleClose}>
  <View align="center" justify="center" height="100%">
    <View padding={6} backgroundColor="neutral" borderRadius="medium">
      <Text>Content with blurred background</Text>
    </View>
  </View>
</Overlay>

Custom Opacity

<Overlay transparent={0.3} active={active} onClose={handleClose}>
  <View align="center" justify="center" height="100%">
    <Text>30% opacity overlay</Text>
  </View>
</Overlay>
function Lightbox({ images, initialIndex = 0 }) {
  const [active, setActive] = React.useState(false);
  const [currentIndex, setCurrentIndex] = React.useState(initialIndex);

  return (
    <>
      <Button onClick={() => setActive(true)}>View Gallery</Button>
      
      <Overlay
        active={active}
        onClose={() => setActive(false)}
        transparent={0.95}
      >
        <View height="100%" align="center" justify="center" gap={4}>
          <View position="relative">
            <Image
              src={images[currentIndex]}
              attributes={{
                style: { maxHeight: '80vh', maxWidth: '90vw' },
              }}
            />
          </View>
          
          <View direction="row" gap={2}>
            <Button
              onClick={() => setCurrentIndex(Math.max(0, currentIndex - 1))}
              disabled={currentIndex === 0}
            >
              Previous
            </Button>
            <Button
              onClick={() => setCurrentIndex(Math.min(images.length - 1, currentIndex + 1))}
              disabled={currentIndex === images.length - 1}
            >
              Next
            </Button>
            <Button onClick={() => setActive(false)}>
              Close
            </Button>
          </View>
        </View>
      </Overlay>
    </>
  );
}

Loading Overlay

function LoadingOverlay({ active }) {
  return (
    <Overlay
      active={active}
      transparent={0.5}
      disableCloseOnClick
    >
      <View
        height="100%"
        align="center"
        justify="center"
        onClick={(e) => e.stopPropagation()}
      >
        <View gap={3} align="center">
          <Loader size="large" color="primary" ariaLabel="Loading" />
          <Text variant="body-2">Processing...</Text>
        </View>
      </View>
    </Overlay>
  );
}

Render Props Pattern

<Overlay active={active}>
  {({ active }) => (
    <View
      height="100%"
      align="center"
      justify="center"
      attributes={{
        style: {
          opacity: active ? 1 : 0,
          transform: active ? 'scale(1)' : 'scale(0.95)',
          transition: 'all 0.2s',
        },
      }}
    >
      <Text>Animated content</Text>
    </View>
  )}
</Overlay>

Contained Overlay

function ContainedOverlay() {
  const containerRef = React.useRef();
  const [active, setActive] = React.useState(false);

  return (
    <View
      attributes={{ ref: containerRef }}
      height="400px"
      position="relative"
      overflow="hidden"
      borderRadius="medium"
      backgroundColor="neutral-faded"
    >
      <View padding={4}>
        <Button onClick={() => setActive(true)}>
          Open Overlay
        </Button>
      </View>
      
      <Overlay
        containerRef={containerRef}
        active={active}
        onClose={() => setActive(false)}
      >
        <View height="100%" align="center" justify="center">
          <View padding={4} backgroundColor="neutral" borderRadius="medium">
            <Text>Contained within parent</Text>
            <Button onClick={() => setActive(false)}>Close</Button>
          </View>
        </View>
      </Overlay>
    </View>
  );
}

Video Player Overlay

function VideoOverlay({ videoUrl }) {
  const [active, setActive] = React.useState(false);

  return (
    <>
      <Button onClick={() => setActive(true)} icon={IconPlay}>
        Watch Video
      </Button>
      
      <Overlay
        active={active}
        onClose={() => setActive(false)}
        transparent
      >
        <View height="100%" align="center" justify="center" padding={4}>
          <View
            width="100%"
            attributes={{ style: { maxWidth: '1200px' } }}
          >
            <video
              src={videoUrl}
              controls
              autoPlay
              style={{ width: '100%', borderRadius: '8px' }}
            />
          </View>
        </View>
      </Overlay>
    </>
  );
}

Custom Close Button

function OverlayWithClose() {
  const [active, setActive] = React.useState(false);

  return (
    <Overlay
      active={active}
      onClose={() => setActive(false)}
    >
      <View height="100%" align="center" justify="center">
        <View position="relative" padding={6} backgroundColor="neutral" borderRadius="medium">
          <Button
            variant="ghost"
            icon={IconX}
            onClick={() => setActive(false)}
            attributes={{
              style: {
                position: 'absolute',
                top: '8px',
                right: '8px',
              },
            }}
          />
          
          <View gap={3}>
            <Text variant="title-5">Content</Text>
            <Text>Overlay content here</Text>
          </View>
        </View>
      </View>
    </Overlay>
  );
}

Prevent Close

function PersistentOverlay() {
  const [active, setActive] = React.useState(false);

  return (
    <Overlay
      active={active}
      disableCloseOnClick
      onClose={({ reason }) => {
        // Only allow close via button, not Escape or outside click
        if (reason !== 'escape-key' && reason !== 'overlay-click') {
          setActive(false);
        }
      }}
    >
      <View height="100%" align="center" justify="center">
        <View padding={6} backgroundColor="neutral" borderRadius="medium">
          <Text>Click the button to close</Text>
          <Button onClick={() => setActive(false)}>Close</Button>
        </View>
      </View>
    </Overlay>
  );
}

When to Use

Use Overlay for:
  • Building custom modal-like components
  • Lightboxes and media viewers
  • Full-screen loading states
  • Custom overlay patterns not covered by Modal
Don’t use Overlay for:
  • Standard dialogs (use Modal)
  • Floating menus (use DropdownMenu)
  • Tooltips (use Tooltip)
  • Popovers (use Popover)

Accessibility

  • Locks body scroll when active
  • Pressing Escape closes the overlay
  • Clicking outside closes by default
  • Provide proper focus management in your content
  • Add appropriate ARIA attributes via attributes
  • Ensure keyboard accessibility for interactive content

Build docs developers (and LLMs) love