← Components/Overlays

Modal

modal-1779394643382.tsx
'use client'
import { useState, useEffect } from 'react'

export default function Modal({
  title = 'Confirm Action',
  body = 'Are you sure you want to proceed? This action cannot be undone.',
  confirmLabel = 'Confirm',
  cancelLabel = 'Cancel',
  danger = false,
}) {
  const [open, setOpen] = useState(false)
  const [loading, setLoading] = useState(false)
  useEffect(() => {
    if (open) document.body.style.overflow = 'hidden'
    else document.body.style.overflow = ''
    return () => { document.body.style.overflow = '' }
  }, [open])
  const confirm = () => {
    setLoading(true)
    setTimeout(() => { setLoading(false); setOpen(false) }, 1500)
  }
  return (
    <>
      <button onClick={()=>setOpen(true)} style={{ background:danger?'#ef4444':'#6d28d9', color:'#fff', border:'none', borderRadius:'10px', padding:'10px 22px', cursor:'pointer', fontWeight:700, fontSize:'14px' }}>
        Open Modal
      </button>
      {open && (
        <div style={{ position:'fixed', inset:0, zIndex:1000, display:'flex', alignItems:'center', justifyContent:'center', padding:'20px' }}>
          <div onClick={()=>setOpen(false)} style={{ position:'absolute', inset:0, background:'rgba(0,0,0,0.5)', backdropFilter:'blur(4px)' }}/>
          <div style={{
            position:'relative', background:'#fff', borderRadius:'20px',
            padding:'28px 24px', maxWidth:'420px', width:'100%',
            boxShadow:'0 25px 80px rgba(0,0,0,0.3)',
            animation:'slideUp 0.25s ease',
          }}>
            <style>{'@keyframes slideUp{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:none}}'}</style>
            <div style={{ fontSize:'32px', marginBottom:'14px' }}>{danger?'⚠️':'ℹ️'}</div>
            <h2 style={{ margin:'0 0 10px', fontSize:'18px', fontWeight:700, color:'#1e293b' }}>{title}</h2>
            <p style={{ margin:'0 0 24px', fontSize:'14px', color:'#64748b', lineHeight:1.6 }}>{body}</p>
            <div style={{ display:'flex', gap:'10px', justifyContent:'flex-end' }}>
              <button onClick={()=>setOpen(false)} style={{ padding:'9px 20px', border:'1px solid #e2e8f0', borderRadius:'10px', background:'#fff', cursor:'pointer', fontWeight:600, color:'#374151', fontSize:'14px' }}>{cancelLabel}</button>
              <button onClick={confirm} disabled={loading} style={{ padding:'9px 20px', border:'none', borderRadius:'10px', background:danger?'#ef4444':'#6d28d9', color:'#fff', cursor:loading?'wait':'pointer', fontWeight:700, fontSize:'14px', minWidth:'90px' }}>
                {loading ? '⏳' : confirmLabel}
              </button>
            </div>
          </div>
        </div>
      )}
    </>
  )
}

Component info

CategoryOverlays
Frameworkreact
TierFREE
Views0
Copies0

About

Accessible modal dialog with backdrop, focus trap and animations

More from Overlays

'use client';

import React, { useState } from 'react';

interface AlertDialogProps {
  isOpen: boolean;
  onClose: () => void;
  onConfirm: () => void;
  title: string;
  description: string;
}

const AlertDialog: React.FC<AlertDialogProps> = ({
  i
AlertDialog
Overlays
'use client';

import { useState, useEffect } from 'react';

interface Command {
  id: number;
  title: string;
  description: string;
}

const commands: Command[] = [
  { id: 1, title: 'New File', description: 'Create a new file' },
  { id: 2, title
CommandPalette
Overlays
'use client'
import { useState, useEffect } from 'react'

const notifications = [
  { id: 1, type: '🎉', title: 'New component published', time: '2m ago', read: false },
  { id: 2, type: '💰', title: 'Pro subscription active', time: '1h ago', read: f
DrawerPanel
Overlays
'use client';

import { useState } from 'react';

interface BottomSheetProps {
  isOpen: boolean;
  onClose: () => void;
}

const BottomSheet = ({ isOpen, onClose }: BottomSheetProps) => {
  const [isDragging, setIsDragging] = useState(false);
  cons
BottomSheet
Overlays