Dialog

A flexible, customizable modal dialog component with keyboard shortcuts, backdrop blur, and smooth animations. Perfect for presenting important information, user interactions, or triggering actions while maintaining focus on modal content.

1"use client";
2
3import Dialog from '@/components/component-x/dialog';
4import { Button } from '@/components/ui/button';
5import { useState } from 'react';
6
7export function DialogPreview() {
8const [isDialogVisible, setIsDialogVisible] = useState(false);
9
10return (
11  <>
12    <Button onClick={() => setIsDialogVisible(true)}>Open Dialog</Button>
13    <Dialog
14      isDialogVisible={isDialogVisible}
15      setIsDialogVisible={setIsDialogVisible}
16    >
17      <div className="p-6 space-y-4">
18        <h2 className="text-2xl font-semibold">Dialog Title</h2>
19        <p className="text-muted-foreground">
20          This is a simple dialog component with backdrop blur and smooth
21          animations.
22        </p>
23        <Button onClick={() => setIsDialogVisible(false)}>Close Dialog</Button>
24      </div>
25    </Dialog>
26  </>
27);
28}
29

Installation

Run the following command to add the component:

npx cx add dialog

Basic Dialog

1"use client";
2
3import Dialog from '@/components/component-x/dialog';
4import { Button } from '@/components/ui/button';
5import { useState } from 'react';
6
7export function BasicDialog() {
8const [isDialogVisible, setIsDialogVisible] = useState(false);
9
10return (
11  <>
12    <Button variant="outline" onClick={() => setIsDialogVisible(true)}>
13      Open Dialog
14    </Button>
15    <Dialog
16      isDialogVisible={isDialogVisible}
17      setIsDialogVisible={setIsDialogVisible}
18    >
19      <div className="p-6">
20        <h2 className="text-xl font-semibold mb-2">Confirm Action</h2>
21        <p className="text-muted-foreground mb-6">
22          Are you sure you want to proceed with this action?
23        </p>
24        <div className="flex gap-3 justify-end">
25          <Button variant="outline" onClick={() => setIsDialogVisible(false)}>
26            Cancel
27          </Button>
28          <Button onClick={() => setIsDialogVisible(false)}>Confirm</Button>
29        </div>
30      </div>
31    </Dialog>
32  </>
33);
34}
35

With Keyboard Shortcut

1"use client";
2
3import Dialog from '@/components/component-x/dialog';
4import { Button } from '@/components/ui/button';
5import { Command } from 'lucide-react';
6import { useState } from 'react';
7
8export function DialogWithShortcut() {
9const [isDialogVisible, setIsDialogVisible] = useState(false);
10
11return (
12  <>
13    <Button variant="outline" onClick={() => setIsDialogVisible(true)}>
14      <span className="text-muted-foreground">Open</span>
15      <span className="flex items-center gap-1 bg-muted/60 p-1 rounded ml-2">
16        <Command size={14} /> K
17      </span>
18    </Button>
19    <Dialog
20      isDialogVisible={isDialogVisible}
21      setIsDialogVisible={setIsDialogVisible}
22      keyToMakeDialogVisible="k"
23    >
24      <div className="p-6 space-y-4">
25        <div>
26          <h2 className="text-xl font-semibold">Quick Search</h2>
27          <p className="text-sm text-muted-foreground">
28            Press Cmd/Ctrl + K to open this dialog anytime
29          </p>
30        </div>
31        <p className="text-muted-foreground">
32          This dialog can be opened with a keyboard shortcut for quick access.
33        </p>
34      </div>
35    </Dialog>
36  </>
37);
38}
39

Custom Size

1"use client";
2
3import Dialog from '@/components/component-x/dialog';
4import { Button } from '@/components/ui/button';
5import { useState } from 'react';
6
7export function DialogCustomSize() {
8const [smallOpen, setSmallOpen] = useState(false);
9const [largeOpen, setLargeOpen] = useState(false);
10
11return (
12  <div className="flex gap-4">
13    <Button variant="outline" onClick={() => setSmallOpen(true)}>
14      Small Dialog
15    </Button>
16    <Dialog
17      isDialogVisible={smallOpen}
18      setIsDialogVisible={setSmallOpen}
19      className="max-w-sm"
20    >
21      <div className="p-4">
22        <h2 className="text-lg font-semibold mb-2">Small Dialog</h2>
23        <p className="text-sm text-muted-foreground">
24          This is a compact dialog perfect for quick confirmations.
25        </p>
26        <Button
27          size="sm"
28          className="mt-4 w-full"
29          onClick={() => setSmallOpen(false)}
30        >
31          Close
32        </Button>
33      </div>
34    </Dialog>
35
36    <Button variant="outline" onClick={() => setLargeOpen(true)}>
37      Large Dialog
38    </Button>
39    <Dialog
40      isDialogVisible={largeOpen}
41      setIsDialogVisible={setLargeOpen}
42      className="max-w-2xl"
43    >
44      <div className="p-8">
45        <h2 className="text-2xl font-semibold mb-4">Large Dialog</h2>
46        <p className="text-muted-foreground mb-6">
47          This is a spacious dialog suitable for detailed content, forms, or
48          rich information displays.
49        </p>
50        <Button onClick={() => setLargeOpen(false)}>Close</Button>
51      </div>
52    </Dialog>
53  </div>
54);
55}
56

Search Dialog

1"use client";
2
3import Dialog from '@/components/component-x/dialog';
4import { Button } from '@/components/ui/button';
5import { Input } from '@/components/ui/input';
6import { Command, Search } from 'lucide-react';
7import { useState } from 'react';
8
9export function SearchDialog() {
10const [isDialogVisible, setIsDialogVisible] = useState(false);
11const [query, setQuery] = useState("");
12
13const results = ["Home", "About", "Services", "Contact", "Blog"];
14const filtered = results.filter((item) =>
15  item.toLowerCase().includes(query.toLowerCase())
16);
17
18return (
19  <>
20    <Button variant="outline" onClick={() => setIsDialogVisible(true)}>
21      <span className="text-muted-foreground">Search</span>
22      <span className="flex items-center gap-1 bg-muted/60 p-1 rounded ml-2">
23        <Command size={14} /> M
24      </span>
25    </Button>
26    <Dialog
27      isDialogVisible={isDialogVisible}
28      setIsDialogVisible={setIsDialogVisible}
29      keyToMakeDialogVisible="m"
30    >
31      <div className="border-b p-4">
32        <div className="relative">
33          <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-muted-foreground" />
34          <Input
35            autoFocus
36            value={query}
37            onChange={(e) => setQuery(e.target.value)}
38            placeholder="Search..."
39            className="pl-10 border-0 bg-transparent focus-visible:ring-0"
40          />
41        </div>
42      </div>
43      <div className="max-h-64 overflow-y-auto p-2">
44        {filtered.length > 0 ? (
45          filtered.map((item) => (
46            <div
47              key={item}
48              className="p-3 hover:bg-muted/50 rounded cursor-pointer transition-colors"
49              onClick={() => setIsDialogVisible(false)}
50            >
51              {item}
52            </div>
53          ))
54        ) : (
55          <div className="p-8 text-center text-muted-foreground">
56            No results found
57          </div>
58        )}
59      </div>
60    </Dialog>
61  </>
62);
63}
64

Authentication Dialog

1"use client";
2
3import Dialog from '@/components/component-x/dialog';
4import { Button } from '@/components/ui/button';
5import { Separator } from '@/components/ui/separator';
6import { Command } from 'lucide-react';
7import { useState } from 'react';
8import { FaGithub } from 'react-icons/fa';
9import Image from 'next/image';
10
11export function AuthDialog() {
12const [isDialogVisible, setIsDialogVisible] = useState(false);
13const [isLoading, setIsLoading] = useState(false);
14
15const handleAuth = async () => {
16  setIsLoading(true);
17  await new Promise((resolve) => setTimeout(resolve, 1000));
18  setIsLoading(false);
19  setIsDialogVisible(false);
20};
21
22return (
23  <>
24    <Button variant="outline" onClick={() => setIsDialogVisible(true)}>
25      <span className="text-muted-foreground">Sign In</span>
26      <span className="flex items-center gap-1 bg-muted/60 p-1 rounded ml-2">
27        <Command size={14} /> A
28      </span>
29    </Button>
30    <Dialog
31      isDialogVisible={isDialogVisible}
32      setIsDialogVisible={setIsDialogVisible}
33      keyToMakeDialogVisible="a"
34      className="max-w-[400px]"
35    >
36      <div className="space-y-4 p-6 text-center">
37        <div className="space-y-2 mb-6">
38          <h1 className="text-2xl font-semibold">Welcome Back</h1>
39          <p className="text-sm text-muted-foreground">
40            Sign in to your account to continue
41          </p>
42        </div>
43        <Button
44          onClick={handleAuth}
45          disabled={isLoading}
46          variant="outline"
47          className="w-full bg-transparent"
48        >
49          <FaGithub className="mr-2 h-4 w-4" />
50          {isLoading ? "Signing in..." : "Continue with GitHub"}
51        </Button>
52        <div className="relative flex gap-1">
53          <span className="flex-1 flex items-center">
54            <Separator />
55          </span>
56          <span className="text-muted-foreground text-sm">Or</span>
57          <span className="flex-1 flex items-center">
58            <Separator />
59          </span>
60        </div>
61        <Button onClick={handleAuth} disabled={isLoading} className="w-full">
62          <Image
63            src="https://www.gstatic.com/firebasejs/ui/2.0.0/images/auth/google.svg"
64            alt="Google"
65            width={16}
66            height={16}
67            className="mr-2"
68          />
69          {isLoading ? "Signing in..." : "Continue with Google"}
70        </Button>
71      </div>
72    </Dialog>
73  </>
74);
75}
76