omverse-ui

Menu

ComponentsExamplesGitHub

Getting started

IntroductionInstallationThemingDesign tokensDark mode

Form

ButtonInputSelectCheckboxRadioSwitchSlidernewDatePickernew

Display

AvatarBadgeCardChipAccordionProgressDivider

Navigation

NavbarBreadcrumbTabsPaginationStepper

Overlay

DialogTooltipToast

Other

IconIconButtonSpinner
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 visible
onClose() => voidCalled when dialog should close (ESC, backdrop, close button)
type'default' | 'destructive' | 'success' | 'warning' | 'info''default'Affects icon and color scheme
position'center' | 'bottom' | 'left' | 'right''center'Where the dialog appears on screen
size'xs' | 'sm' | 'md' | 'lg' | 'fullscreen''md'Width of the dialog panel (fullscreen = entire viewport)
titlestringTitle shown in the dialog header
subtitlestringSubtitle shown below the title
iconstringEmoji or icon shown above the title
imageSrcstringHero image URL shown at the top of the dialog
imageAltstringAlt text for the hero image
imageHeightnumber160Height of the hero image in px
showCloseButtonbooleantrueShows the × close button in the header
closeOnBackdropbooleantrueCloses dialog when clicking the backdrop
closeOnEscapebooleantrueCloses dialog on Escape key
footerReactNodeFooter content — usually action buttons
footerDividerbooleantrueShows a divider between body and footer
childrenReactNodeDialog body content