Modal
Modal dialog for focusing user attention on important content.
import { Modal, Button } from "ui-lab-components";
import { useState } from "react";
export function Example() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button onClick={() => setIsOpen(true)}>
Open Modal
</Button>
<Modal isOpen={isOpen} onOpenChange={setIsOpen}>
<Modal.Header>Modal Title</Modal.Header>
<Modal.Body>Modal content goes here</Modal.Body>
</Modal>
</>
);
}Basic Modal
A simple modal dialog with a trigger button. Use this for important user interactions that require focused attention.
'use client';
import React from 'react';
import { Modal, Button } from 'ui-lab-components';
export const metadata = {
title: 'Basic Modal',
description: 'A simple modal dialog with a trigger button. Use this for important user interactions that require focused attention.'
};
export default function Example() {
const [isOpen, setIsOpen] = React.useState(false);
return (
<>
<Button onClick={() => setIsOpen(true)}>Open Modal</Button>
<Modal isOpen={isOpen} onOpenChange={setIsOpen}>
<Modal.Header>Modal Title</Modal.Header>
<Modal.Body>This is the modal content. It displays important information or actions.</Modal.Body>
<Modal.Footer>Modal Footer</Modal.Footer>
</Modal>
</>
);
}
Form Modal
A modal dialog containing a form for editing user profile settings.
'use client';
import React from 'react';
import { Modal, Button, Input, Label, TextArea, Flex } from 'ui-lab-components';
export const metadata = {
title: 'Form Modal',
description: 'A modal dialog containing a form for editing user profile settings. Demonstrates using form inputs, labels, and action buttons within a modal.'
};
export default function Example() {
const [isOpen, setIsOpen] = React.useState(false);
const [formData, setFormData] = React.useState({
name: 'John Doe',
email: 'john.doe@example.com',
bio: 'Software developer passionate about building great user experiences.',
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
// Handle form submission
setIsOpen(false);
};
return (
<>
<Button onClick={() => setIsOpen(true)}>Edit Profile</Button>
<Modal isOpen={isOpen} onOpenChange={setIsOpen} size="auto">
<Modal.Header>Edit Profile</Modal.Header>
<Modal.Body>
<form id="profile-form" onSubmit={handleSubmit}>
<Flex direction="column" gap="md">
<div>
<Label htmlFor="name" required>
Full Name
</Label>
<Input
id="name"
value={formData.name}
onChange={(e) =>
setFormData({ ...formData, name: e.target.value })
}
placeholder="Enter your name"
/>
</div>
<div>
<Label htmlFor="email" required>
Email Address
</Label>
<Input
id="email"
type="email"
value={formData.email}
onChange={(e) =>
setFormData({ ...formData, email: e.target.value })
}
placeholder="Enter your email"
/>
</div>
<div>
<Label htmlFor="bio">Bio</Label>
<TextArea
id="bio"
value={formData.bio}
onChange={(e) =>
setFormData({ ...formData, bio: e.target.value })
}
placeholder="Tell us about yourself"
rows={3}
/>
</div>
</Flex>
</form>
</Modal.Body>
<Modal.Footer>
<Flex gap="sm" justify="end">
<Button variant="ghost" onClick={() => setIsOpen(false)}>
Cancel
</Button>
<Button type="submit" form="profile-form">
Save Changes
</Button>
</Flex>
</Modal.Footer>
</Modal>
</>
);
}
Delete Confirmation
Destructive action dialog that blocks the user until they explicitly confirm or cancel.
"use client";
import { useState } from "react";
import { Modal, Button } from "ui-lab-components";
export const metadata = {
title: "Delete Confirmation",
description: "Destructive action dialog that blocks the user until they explicitly confirm or cancel.",
};
export default function Example() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button variant="destructive" onClick={() => setIsOpen(true)}>
Delete workspace
</Button>
<Modal
isOpen={isOpen}
onOpenChange={setIsOpen}
title="Delete workspace"
footer={
<>
<Button variant="ghost" onClick={() => setIsOpen(false)}>
Cancel
</Button>
<Button variant="destructive" onClick={() => setIsOpen(false)}>
Delete
</Button>
</>
}
>
<p className="text-sm text-foreground-300">
This will permanently delete <strong className="text-foreground-100">acme-corp</strong> and all
its data. This action cannot be undone.
</p>
</Modal>
</>
);
}
Create API Key
Form modal with a single required input. The primary action stays disabled until the field has a value.
"use client";
import { useState } from "react";
import { Modal, Button, Input, Label } from "ui-lab-components";
export const metadata = {
title: "Create API Key",
description: "Form modal with a single required input. The primary action stays disabled until the field has a value.",
};
export default function Example() {
const [isOpen, setIsOpen] = useState(false);
const [name, setName] = useState("");
return (
<>
<Button onClick={() => setIsOpen(true)}>New API key</Button>
<Modal
isOpen={isOpen}
onOpenChange={setIsOpen}
title="New API key"
footer={
<>
<Button variant="ghost" onClick={() => setIsOpen(false)}>
Cancel
</Button>
<Button
onClick={() => setIsOpen(false)}
isDisabled={!name.trim()}
>
Create
</Button>
</>
}
>
<div className="flex flex-col gap-4 px-6 py-4">
<div className="flex flex-col gap-1.5">
<Label htmlFor="key-name">Name</Label>
<Input
id="key-name"
placeholder="e.g. CI deploy key"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
<p className="text-xs text-foreground-400">
The key will only be shown once after creation.
</p>
</div>
</Modal>
</>
);
}
Notification Settings
Settings panel using the compound Modal.Header / Modal.Body / Modal.Footer API with toggle rows.
"use client";
import { useState } from "react";
import { Modal, Button, Switch } from "ui-lab-components";
export const metadata = {
title: "Notification Settings",
description: "Settings panel using the compound Modal.Header / Modal.Body / Modal.Footer API with toggle rows.",
};
export default function Example() {
const [isOpen, setIsOpen] = useState(false);
const [prefs, setPrefs] = useState({ email: true, push: false, marketing: false });
const toggle = (key: keyof typeof prefs) =>
setPrefs((p) => ({ ...p, [key]: !p[key] }));
return (
<>
<Button variant="ghost" onClick={() => setIsOpen(true)}>
Notification settings
</Button>
<Modal isOpen={isOpen} onOpenChange={setIsOpen}>
<Modal.Header>
<span className="text-sm font-semibold text-foreground-100">Notification preferences</span>
</Modal.Header>
<Modal.Body>
<div className="flex flex-col divide-y divide-border px-6">
{(
[
{ key: "email", label: "Email notifications", description: "Receive updates and alerts by email" },
{ key: "push", label: "Push notifications", description: "Browser and mobile push alerts" },
{ key: "marketing", label: "Product updates", description: "New features and announcements" },
] as const
).map(({ key, label, description }) => (
<div key={key} className="flex items-center justify-between py-4">
<div className="flex flex-col gap-0.5">
<span className="text-sm text-foreground-100">{label}</span>
<span className="text-xs text-foreground-400">{description}</span>
</div>
<Switch isSelected={prefs[key]} onChange={() => toggle(key)} />
</div>
))}
</div>
</Modal.Body>
<Modal.Footer>
<Button variant="ghost" onClick={() => setIsOpen(false)}>
Cancel
</Button>
<Button onClick={() => setIsOpen(false)}>Save</Button>
</Modal.Footer>
</Modal>
</>
);
}