ComponentsOverlayDialog
Dialog
5 types · 4 positions · 5 sizes · form · image header · multi-step · command palette
Alert typesFormImage headerBottom drawerRight panelFullscreenMulti-stepCommand palette
Alert types
Live preview
type prop sets the icon and color scheme — default, destructive, success, warning
App.tsx
tsx
1import { Dialog, Button } from 'omverse-ui'
2
3{/* Default */}
4<Dialog
5 open={basic}
6 onClose={() => setBasic(false)}
7 size="sm"
8 showCloseButton
9 footer={
10 <div style={{ display: 'flex', gap: 12, width: '100%' }}>
11 <Button variant="outlined" style={{ flex: 1 }} onClick={() => setBasic(false)}>Dismiss</Button>
12 <Button variant="filled" style={{ flex: 1 }} onClick={() => setBasic(false)}>Get started</Button>
13 </div>
14 }
15>
16 <p>Welcome back, John!</p>
17</Dialog>
18
19{/* Destructive */}
20<Dialog
21 open={destructive}
22 onClose={() => setDestructive(false)}
23 type="destructive"
24 size="sm"
25 showCloseButton={false}
26 footer={
27 <div style={{ display: 'flex', gap: 12, width: '100%' }}>
28 <Button variant="outlined" style={{ flex: 1 }} onClick={() => setDestructive(false)}>Cancel</Button>
29 <Button variant="filled" color="error" style={{ flex: 1 }} onClick={() => setDestructive(false)}>Yes, delete account</Button>
30 </div>
31 }
32>
33 <p>This action cannot be undone.</p>
34</Dialog>
35
36{/* Success */}
37<Dialog
38 open={success}
39 onClose={() => setSuccess(false)}
40 type="success"
41 size="xs"
42 showCloseButton={false}
43 footer={
44 <Button variant="filled" color="success" style={{ width: '100%' }} onClick={() => setSuccess(false)}>
45 Continue
46 </Button>
47 }
48>
49 <p>Payment of $49.00 processed successfully.</p>
50</Dialog>
51
52{/* Warning */}
53<Dialog
54 open={warning}
55 onClose={() => setWarning(false)}
56 type="warning"
57 size="xs"
58 showCloseButton={false}
59 footer={
60 <div style={{ display: 'flex', gap: 12, width: '100%' }}>
61 <Button variant="outlined" style={{ flex: 1 }} onClick={() => setWarning(false)}>Stay on page</Button>
62 <Button variant="filled" color="warning" style={{ flex: 1 }} onClick={() => setWarning(false)}>Leave anyway</Button>
63 </div>
64 }
65>
66 <p>You have unsaved changes that will be lost.</p>
67</Dialog>
Form + image header
Live preview
Form dialog with Input fields; imageSrc places a hero banner at the top
App.tsx
tsx
1import { Dialog, Button, Input } from 'omverse-ui'
2
3{/* Form dialog */}
4<Dialog
5 open={form}
6 onClose={() => setForm(false)}
7 title="Invite team member"
8 subtitle="They'll receive an email invitation"
9 size="sm"
10 footer={
11 <>
12 <Button variant="outlined" onClick={() => setForm(false)}>Cancel</Button>
13 <Button variant="filled" onClick={() => setForm(false)}>Send invite</Button>
14 </>
15 }
16>
17 <div style={{ display: 'flex', flexDirection: 'column', gap: 16, padding: '16px 24px' }}>
18 <Input label="Email address" placeholder="colleague@company.com" leadingIcon="mail" />
19 <Input label="Full name" placeholder="John Doe" />
20 </div>
21</Dialog>
22
23{/* Image header dialog */}
24<Dialog
25 open={image}
26 onClose={() => setImage(false)}
27 imageSrc="https://picsum.photos/seed/upgrade/600/160"
28 imageAlt="Upgrade to Pro"
29 title="Upgrade to Pro"
30 subtitle="Unlock all features"
31 size="sm"
32 footer={
33 <>
34 <Button variant="text" onClick={() => setImage(false)}>Maybe later</Button>
35 <Button variant="filled" onClick={() => setImage(false)}>Upgrade now</Button>
36 </>
37 }
38>
39 <p style={{ padding: '16px 24px', fontSize: 14, color: 'var(--color-text-secondary)' }}>
40 Get unlimited projects, priority support, advanced analytics, and custom domains with Pro.
41 </p>
42</Dialog>
Positions
Live preview
bottom = bottom drawer · right = side panel · size=fullscreen fills the viewport
App.tsx
tsx
1{/* Bottom drawer */}
2<Dialog
3 open={bottom}
4 onClose={() => setBottom(false)}
5 position="bottom"
6 title="Share document"
7 subtitle="Choose how to share"
8 footer={
9 <Button variant="outlined" style={{ width: '100%' }} onClick={() => setBottom(false)}>Cancel</Button>
10 }
11>
12 <div style={{ padding: '16px 24px', display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12 }}>
13 {['Copy link', 'Email', 'Message', 'WhatsApp', 'Twitter', 'LinkedIn'].map(label => (
14 <button key={label} onClick={() => setBottom(false)}
15 style={{ padding: '12px 8px', borderRadius: 12, border: '1px solid var(--color-border)',
16 display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6 }}>
17 <span style={{ fontSize: 13, color: 'var(--color-text-secondary)' }}>{label}</span>
18 </button>
19 ))}
20 </div>
21</Dialog>
22
23{/* Right panel */}
24<Dialog
25 open={right}
26 onClose={() => setRight(false)}
27 position="right"
28 title="Edit profile"
29 subtitle="Update your information"
30 footer={
31 <>
32 <Button variant="outlined" onClick={() => setRight(false)}>Cancel</Button>
33 <Button variant="filled" onClick={() => setRight(false)}>Save changes</Button>
34 </>
35 }
36>
37 <div style={{ display: 'flex', flexDirection: 'column', gap: 16, padding: '16px 24px' }}>
38 <Input label="Full name" defaultValue="John Doe" />
39 <Input label="Role" defaultValue="Product Designer" />
40 <Input label="Email" defaultValue="john@example.com" leadingIcon="mail" />
41 </div>
42</Dialog>
43
44{/* Fullscreen — size="fullscreen" with position="center" */}
45<Dialog
46 open={fullscreen}
47 onClose={() => setFullscreen(false)}
48 position="center"
49 size="fullscreen"
50 title="Full screen dialog"
51 subtitle="Takes up the entire screen"
52 footer={
53 <Button variant="outlined" onClick={() => setFullscreen(false)}>Close</Button>
54 }
55>
56 <p style={{ padding: '16px 24px', fontSize: 14, color: 'var(--color-text-secondary)' }}>
57 Useful for complex workflows or immersive content.
58 </p>
59</Dialog>
Multi-step
Live preview
Step indicator + back/next footer — built with a single step state
App.tsx
tsx
1const [multiStep, setMultiStep] = useState(false)
2const [step, setStep] = useState(1)
3
4<Dialog
5 open={multiStep}
6 onClose={() => setMultiStep(false)}
7 title={`Create project — Step ${step} of 3`}
8 subtitle={['Name your project', 'Configure settings', 'Invite team'][step - 1]}
9 size="sm"
10 showCloseButton
11 footer={
12 <div style={{ display: 'flex', justifyContent: 'space-between', width: '100%' }}>
13 <Button variant="outlined"
14 onClick={() => step === 1 ? setMultiStep(false) : setStep(s => s - 1)}>
15 {step === 1 ? 'Cancel' : '← Back'}
16 </Button>
17 <Button variant="filled"
18 onClick={() => step === 3 ? setMultiStep(false) : setStep(s => s + 1)}>
19 {step === 3 ? 'Create project' : 'Next →'}
20 </Button>
21 </div>
22 }
23>
24 <div style={{ padding: '16px 24px' }}>
25 {/* Step indicator */}
26 <div style={{ display: 'flex', alignItems: 'center', gap: 0, marginBottom: 24 }}>
27 {[1, 2, 3].map((s, i) => (
28 <div key={s} style={{ display: 'flex', alignItems: 'center', flex: i < 2 ? 1 : 'none' }}>
29 <div style={{
30 width: 28, height: 28, borderRadius: '50%', flexShrink: 0,
31 display: 'flex', alignItems: 'center', justifyContent: 'center',
32 fontSize: 12, fontWeight: 600,
33 background: s < step ? 'var(--color-primary)' : s === step ? 'var(--color-primary-container)' : 'var(--color-surface-variant)',
34 color: s < step ? '#fff' : s === step ? 'var(--color-primary)' : 'var(--color-text-disabled)',
35 border: s === step ? '2px solid var(--color-primary)' : 'none',
36 }}>
37 {s < step ? '✓' : s}
38 </div>
39 {i < 2 && (
40 <div style={{ flex: 1, height: 2, background: s < step ? 'var(--color-primary)' : 'var(--color-border)' }} />
41 )}
42 </div>
43 ))}
44 </div>
45 {step === 1 && <Input label="Project name" placeholder="My awesome project" />}
46 {step === 2 && <Input label="Description" placeholder="What is this project about?" />}
47 {step === 3 && <Input label="Invite teammates" placeholder="email@company.com" leadingIcon="mail" helperText="Separate multiple emails with commas" />}
48 </div>
49</Dialog>
Command palette
Live preview
⌘K-style search overlay — built with Dialog + search input + command items
App.tsx
tsx
1const [command, setCommand] = useState(false)
2
3const commands = [
4 { icon: 'ti-file', label: 'New file', shortcut: '⌘N', group: 'Create' },
5 { icon: 'ti-folder', label: 'Open folder', shortcut: '⌘O', group: 'Create' },
6 { icon: 'ti-search', label: 'Find in files', shortcut: '⌘⇧F', group: 'Search' },
7 { icon: 'ti-settings', label: 'Settings', shortcut: '⌘,', group: 'Navigation' },
8 { icon: 'ti-terminal', label: 'New terminal', shortcut: '⌘⇧`', group: 'Navigation' },
9]
10
11<Button variant="filled" onClick={() => setCommand(true)}>
12 Command palette ⌘K
13</Button>
14
15<Dialog
16 open={command}
17 onClose={() => setCommand(false)}
18 showCloseButton={false}
19 size="sm"
20>
21 <div style={{ padding: '8px 0' }}>
22 {/* Search input */}
23 <div style={{ padding: '8px 16px 10px', borderBottom: '0.5px solid var(--color-border-tertiary)', display: 'flex', alignItems: 'center', gap: 8 }}>
24 <i className="ti ti-search" style={{ fontSize: 16, color: 'var(--color-text-secondary)', flexShrink: 0 }} aria-hidden="true" />
25 <input
26 autoFocus
27 placeholder="Search commands..."
28 style={{
29 flex: 1,
30 background: 'none',
31 border: 'none',
32 outline: 'none',
33 fontSize: 14,
34 color: 'var(--color-text-primary)',
35 padding: '4px 0',
36 }}
37 />
38 <kbd style={{ fontSize: 11, color: 'var(--color-text-tertiary)', background: 'var(--color-background-secondary)', padding: '2px 6px', borderRadius: 4, border: '0.5px solid var(--color-border-tertiary)' }}>
39 ESC
40 </kbd>
41 </div>
42 {/* Command items */}
43 {commands.map(item => (
44 <div key={item.label} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '8px 16px', cursor: 'pointer', fontSize: 13, color: 'var(--color-text-primary)' }}>
45 <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
46 <i className={`ti ${item.icon}`} style={{ fontSize: 16, color: 'var(--color-text-secondary)' }} aria-hidden="true" />
47 {item.label}
48 </div>
49 <kbd style={{ fontSize: 11, color: 'var(--color-text-tertiary)', background: 'var(--color-background-secondary)', padding: '2px 6px', borderRadius: 4, border: '0.5px solid var(--color-border-tertiary)' }}>
50 {item.shortcut}
51 </kbd>
52 </div>
53 ))}
54 </div>
55</Dialog>
Props
PropTypeDefaultDescription
openbooleanfalseWhether the dialog is visibleonClose() => void—Called when dialog should close (ESC, backdrop, close button)type'default' | 'destructive' | 'success' | 'warning' | 'info''default'Affects icon and color schemeposition'center' | 'bottom' | 'left' | 'right''center'Where the dialog appears on screensize'xs' | 'sm' | 'md' | 'lg' | 'fullscreen''md'Width of the dialog panel (fullscreen = entire viewport)titlestring—Title shown in the dialog headersubtitlestring—Subtitle shown below the titleiconstring—Emoji or icon shown above the titleimageSrcstring—Hero image URL shown at the top of the dialogimageAltstring—Alt text for the hero imageimageHeightnumber160Height of the hero image in pxshowCloseButtonbooleantrueShows the × close button in the headercloseOnBackdropbooleantrueCloses dialog when clicking the backdropcloseOnEscapebooleantrueCloses dialog on Escape keyfooterReactNode—Footer content — usually action buttonsfooterDividerbooleantrueShows a divider between body and footerchildrenReactNode—Dialog body content