Skip to main content

Overlay Components

Modal dialogs, popovers, and menu components for building interactive UI overlays.

Dialog

Modal dialog component for focused interactions.

Preview

Live Editor
function DialogDemo() {
  const [open, setOpen] = React.useState(false);
  
  return (
    <>
      <button
        onClick={() => setOpen(true)}
        style={{
          padding: '10px 20px',
          borderRadius: '8px',
          background: 'linear-gradient(135deg, #8b5cf6 0%, #6366f1 100%)',
          color: 'white',
          border: 'none',
          cursor: 'pointer',
          fontWeight: 600,
        }}
      >
        Open Dialog
      </button>
      
      {open && (
        <div style={{
          position: 'fixed',
          inset: 0,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          backgroundColor: 'rgba(0,0,0,0.4)',
          zIndex: 50,
        }}>
          <div style={{
            background: 'white',
            borderRadius: '12px',
            padding: '24px',
            maxWidth: '400px',
            boxShadow: '0 20px 50px -12px rgba(0,0,0,0.25)',
          }}>
            <h3 style={{ margin: 0, marginBottom: '8px' }}>Edit Profile</h3>
            <p style={{ color: '#64748b', margin: 0, marginBottom: '20px' }}>
              Make changes to your profile here.
            </p>
            <div style={{ display: 'flex', gap: '8px', justifyContent: 'flex-end' }}>
              <button
                onClick={() => setOpen(false)}
                style={{
                  padding: '8px 16px',
                  borderRadius: '6px',
                  border: '1px solid #e2e8f0',
                  background: 'white',
                  cursor: 'pointer',
                }}
              >
                Cancel
              </button>
              <button
                onClick={() => setOpen(false)}
                style={{
                  padding: '8px 16px',
                  borderRadius: '6px',
                  border: 'none',
                  background: '#8b5cf6',
                  color: 'white',
                  cursor: 'pointer',
                }}
              >
                Save
              </button>
            </div>
          </div>
        </div>
      )}
    </>
  );
}
Result
Loading...

Usage

import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
} from "@cpod/react";
import { Button } from "@cpod/react";

<Dialog>
<DialogTrigger asChild>
<Button>Open Dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Edit Profile</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when done.
</DialogDescription>
</DialogHeader>
<div className="py-4">
{/* Form content */}
</div>
<DialogFooter>
<Button variant="outline">Cancel</Button>
<Button>Save changes</Button>
</DialogFooter>
</DialogContent>
</Dialog>

Sub-components

ComponentDescription
DialogRoot component (controlled state)
DialogTriggerButton that opens the dialog
DialogContentMain dialog container
DialogHeaderHeader section
DialogFooterFooter section for actions
DialogTitleDialog title
DialogDescriptionDialog description
DialogCloseClose button

AlertDialog

Confirmation dialog for destructive or important actions.

Preview

Live Editor
function AlertDialogDemo() {
  const [open, setOpen] = React.useState(false);
  
  return (
    <>
      <button
        onClick={() => setOpen(true)}
        style={{
          padding: '10px 20px',
          borderRadius: '8px',
          background: '#ef4444',
          color: 'white',
          border: 'none',
          cursor: 'pointer',
          fontWeight: 600,
        }}
      >
        Delete Account
      </button>
      
      {open && (
        <div style={{
          position: 'fixed',
          inset: 0,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          backgroundColor: 'rgba(0,0,0,0.6)',
          zIndex: 50,
        }}>
          <div style={{
            background: 'white',
            borderRadius: '12px',
            padding: '24px',
            maxWidth: '450px',
            boxShadow: '0 20px 50px -12px rgba(0,0,0,0.25)',
          }}>
            <h3 style={{ margin: 0, marginBottom: '8px' }}>Are you absolutely sure?</h3>
            <p style={{ color: '#64748b', margin: 0, marginBottom: '20px', lineHeight: 1.5 }}>
              This action cannot be undone. This will permanently delete your account
              and remove your data from our servers.
            </p>
            <div style={{ display: 'flex', gap: '8px', justifyContent: 'flex-end' }}>
              <button
                onClick={() => setOpen(false)}
                style={{
                  padding: '8px 16px',
                  borderRadius: '6px',
                  border: '1px solid #e2e8f0',
                  background: 'white',
                  cursor: 'pointer',
                }}
              >
                Cancel
              </button>
              <button
                onClick={() => setOpen(false)}
                style={{
                  padding: '8px 16px',
                  borderRadius: '6px',
                  border: 'none',
                  background: '#ef4444',
                  color: 'white',
                  cursor: 'pointer',
                }}
              >
                Delete Account
              </button>
            </div>
          </div>
        </div>
      )}
    </>
  );
}
Result
Loading...

Usage

import {
AlertDialog,
AlertDialogTrigger,
AlertDialogContent,
AlertDialogHeader,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogAction,
AlertDialogCancel,
} from "@cpod/react";
import { Button } from "@cpod/react";

<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive">Delete Account</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete your
account and remove your data from our servers.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction>Delete Account</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>

Sheet

Side panel overlay that slides in from the edge.

Preview

Live Editor
function SheetDemo() {
  const [open, setOpen] = React.useState(false);
  
  return (
    <>
      <button
        onClick={() => setOpen(true)}
        style={{
          padding: '10px 20px',
          borderRadius: '8px',
          background: 'linear-gradient(135deg, #8b5cf6 0%, #6366f1 100%)',
          color: 'white',
          border: 'none',
          cursor: 'pointer',
          fontWeight: 600,
        }}
      >
        Open Sheet
      </button>
      
      {open && (
        <div style={{
          position: 'fixed',
          inset: 0,
          backgroundColor: 'rgba(0,0,0,0.6)',
          zIndex: 50,
        }}>
          <div 
            onClick={() => setOpen(false)}
            style={{
              position: 'absolute',
              inset: 0,
            }}
          />
          <div style={{
            position: 'absolute',
            right: 0,
            top: 0,
            bottom: 0,
            width: '350px',
            background: 'white',
            padding: '24px',
            boxShadow: '-20px 0 50px -12px rgba(0,0,0,0.25)',
          }}>
            <button
              onClick={() => setOpen(false)}
              style={{
                position: 'absolute',
                right: '16px',
                top: '16px',
                background: 'none',
                border: 'none',
                cursor: 'pointer',
                fontSize: '20px',
                color: '#64748b',
              }}
            >
              ×
            </button>
            <h3 style={{ margin: 0, marginBottom: '8px' }}>Settings</h3>
            <p style={{ color: '#64748b', margin: 0 }}>
              Configure your preferences here.
            </p>
          </div>
        </div>
      )}
    </>
  );
}
Result
Loading...

Usage

import {
Sheet,
SheetTrigger,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
} from "@cpod/react";
import { Button } from "@cpod/react";

// Right side (default)
<Sheet>
<SheetTrigger asChild>
<Button>Open Settings</Button>
</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Settings</SheetTitle>
<SheetDescription>
Configure your account preferences.
</SheetDescription>
</SheetHeader>
<div className="py-4">
{/* Content */}
</div>
</SheetContent>
</Sheet>

// Left side
<Sheet>
<SheetTrigger asChild>
<Button>Open Navigation</Button>
</SheetTrigger>
<SheetContent side="left">
<SheetTitle>Navigation</SheetTitle>
</SheetContent>
</Sheet>

Props

SheetContent:

PropTypeDefaultDescription
sidetop | right | bottom | leftrightSheet position

Popover

Floating content panel anchored to a trigger element.

Preview

Live Editor
function PopoverDemo() {
  const [open, setOpen] = React.useState(false);
  
  return (
    <div style={{ position: 'relative', display: 'inline-block' }}>
      <button
        onClick={() => setOpen(!open)}
        style={{
          padding: '10px 20px',
          borderRadius: '8px',
          background: 'linear-gradient(135deg, #8b5cf6 0%, #6366f1 100%)',
          color: 'white',
          border: 'none',
          cursor: 'pointer',
          fontWeight: 600,
        }}
      >
        Open Popover
      </button>
      
      {open && (
        <div style={{
          position: 'absolute',
          top: '100%',
          left: '50%',
          transform: 'translateX(-50%)',
          marginTop: '8px',
          background: 'white',
          borderRadius: '8px',
          padding: '16px',
          boxShadow: '0 10px 40px -10px rgba(0,0,0,0.2)',
          border: '1px solid #e2e8f0',
          width: '250px',
          zIndex: 50,
        }}>
          <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
            <label style={{ fontSize: '14px', fontWeight: 500 }}>Width</label>
            <input 
              placeholder="100%"
              style={{
                padding: '8px 12px',
                borderRadius: '6px',
                border: '1px solid #e2e8f0',
                fontSize: '14px',
              }}
            />
          </div>
        </div>
      )}
    </div>
  );
}
Result
Loading...

Usage

import {
Popover,
PopoverTrigger,
PopoverContent,
} from "@cpod/react";
import { Button, Input, Label } from "@cpod/react";

<Popover>
<PopoverTrigger asChild>
<Button variant="outline">Open Popover</Button>
</PopoverTrigger>
<PopoverContent className="w-80">
<div className="grid gap-4">
<div className="space-y-2">
<h4 className="font-medium">Dimensions</h4>
<p className="text-sm text-muted-foreground">
Set the dimensions for the layer.
</p>
</div>
<div className="grid gap-2">
<div className="grid grid-cols-3 items-center gap-4">
<Label htmlFor="width">Width</Label>
<Input id="width" defaultValue="100%" className="col-span-2" />
</div>
</div>
</div>
</PopoverContent>
</Popover>

Tooltip

Informational popup on hover.

Preview

Live Editor
function TooltipDemo() {
  const [show, setShow] = React.useState(false);
  
  return (
    <div style={{ position: 'relative', display: 'inline-block' }}>
      <button
        onMouseEnter={() => setShow(true)}
        onMouseLeave={() => setShow(false)}
        style={{
          padding: '10px 20px',
          borderRadius: '8px',
          background: '#1e293b',
          color: 'white',
          border: 'none',
          cursor: 'pointer',
          fontWeight: 600,
        }}
      >
        Hover me
      </button>
      
      {show && (
        <div style={{
          position: 'absolute',
          bottom: '100%',
          left: '50%',
          transform: 'translateX(-50%)',
          marginBottom: '8px',
          background: '#1e293b',
          color: 'white',
          borderRadius: '6px',
          padding: '6px 12px',
          fontSize: '12px',
          whiteSpace: 'nowrap',
          zIndex: 50,
        }}>
          Add to library
        </div>
      )}
    </div>
  );
}
Result
Loading...

Usage

import {
Tooltip,
TooltipTrigger,
TooltipContent,
TooltipProvider,
} from "@cpod/react";
import { Button } from "@cpod/react";

// Wrap your app with TooltipProvider
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">Hover</Button>
</TooltipTrigger>
<TooltipContent>
<p>Add to library</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>

Dropdown menu for actions and navigation.

Preview

Live Editor
function DropdownMenuDemo() {
  const [open, setOpen] = React.useState(false);
  
  return (
    <div style={{ position: 'relative', display: 'inline-block' }}>
      <button
        onClick={() => setOpen(!open)}
        style={{
          padding: '10px 20px',
          borderRadius: '8px',
          background: 'white',
          border: '1px solid #e2e8f0',
          cursor: 'pointer',
          fontWeight: 600,
          display: 'flex',
          alignItems: 'center',
          gap: '8px',
        }}
      >
        Open Menu
        <span style={{ fontSize: '10px' }}></span>
      </button>
      
      {open && (
        <div style={{
          position: 'absolute',
          top: '100%',
          left: 0,
          marginTop: '4px',
          background: 'white',
          borderRadius: '8px',
          boxShadow: '0 10px 40px -10px rgba(0,0,0,0.2)',
          border: '1px solid #e2e8f0',
          minWidth: '160px',
          zIndex: 50,
          padding: '4px',
        }}>
          {['Profile', 'Settings', 'Billing'].map((item) => (
            <div
              key={item}
              style={{
                padding: '8px 12px',
                borderRadius: '4px',
                cursor: 'pointer',
                fontSize: '14px',
              }}
              onMouseEnter={(e) => e.currentTarget.style.background = '#f8fafc'}
              onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
            >
              {item}
            </div>
          ))}
          <div style={{ height: '1px', background: '#e2e8f0', margin: '4px 0' }} />
          <div
            style={{
              padding: '8px 12px',
              borderRadius: '4px',
              cursor: 'pointer',
              fontSize: '14px',
              color: '#ef4444',
            }}
            onMouseEnter={(e) => e.currentTarget.style.background = '#fef2f2'}
            onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
          >
            Log out
          </div>
        </div>
      )}
    </div>
  );
}
Result
Loading...

Usage

import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuCheckboxItem,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuSubContent,
} from "@cpod/react";
import { Button } from "@cpod/react";

<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Open Menu</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56">
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Billing</DropdownMenuItem>
<DropdownMenuItem>Settings</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem className="text-red-600">
Log out
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>

ContextMenu

Right-click context menu.

Preview

Live Editor
function ContextMenuDemo() {
  const [menu, setMenu] = React.useState(null);
  
  return (
    <div
      onContextMenu={(e) => {
        e.preventDefault();
        setMenu({ x: e.clientX, y: e.clientY });
      }}
      onClick={() => setMenu(null)}
      style={{
        padding: '60px 40px',
        background: 'linear-gradient(135deg, rgba(139, 92, 246, 0.1) 0%, rgba(34, 211, 238, 0.1) 100%)',
        borderRadius: '12px',
        border: '2px dashed #8b5cf6',
        textAlign: 'center',
        color: '#64748b',
        fontSize: '14px',
        cursor: 'context-menu',
        position: 'relative',
      }}
    >
      Right-click here
      
      {menu && (
        <div
          style={{
            position: 'fixed',
            top: menu.y,
            left: menu.x,
            background: 'white',
            borderRadius: '8px',
            boxShadow: '0 10px 40px -10px rgba(0,0,0,0.2)',
            border: '1px solid #e2e8f0',
            minWidth: '160px',
            zIndex: 50,
            padding: '4px',
          }}
          onClick={(e) => e.stopPropagation()}
        >
          {['Back', 'Forward', 'Refresh', 'Save As...'].map((item) => (
            <div
              key={item}
              onClick={() => setMenu(null)}
              style={{
                padding: '8px 12px',
                borderRadius: '4px',
                cursor: 'pointer',
                fontSize: '14px',
              }}
              onMouseEnter={(e) => e.currentTarget.style.background = '#f8fafc'}
              onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
            >
              {item}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}
Result
Loading...

Usage

import {
ContextMenu,
ContextMenuTrigger,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuSub,
ContextMenuSubTrigger,
ContextMenuSubContent,
} from "@cpod/react";

<ContextMenu>
<ContextMenuTrigger className="w-full h-40 border-2 border-dashed rounded-lg flex items-center justify-center">
Right-click here
</ContextMenuTrigger>
<ContextMenuContent className="w-64">
<ContextMenuItem>Back</ContextMenuItem>
<ContextMenuItem>Forward</ContextMenuItem>
<ContextMenuItem>Refresh</ContextMenuItem>
<ContextMenuSeparator />
<ContextMenuSub>
<ContextMenuSubTrigger>More Tools</ContextMenuSubTrigger>
<ContextMenuSubContent className="w-48">
<ContextMenuItem>Save Page As...</ContextMenuItem>
<ContextMenuItem>Create Shortcut...</ContextMenuItem>
</ContextMenuSubContent>
</ContextMenuSub>
</ContextMenuContent>
</ContextMenu>