Elliot Sutton

Headless Dialog

Component 3

About

A renderless, fully-managed dialog primitive with built-in accessibility and keyboard support and animated flip transitions, for building completely custom dialogs and alerts.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Headless Dialog to your project and fits it to your theme.

Code

How Headless Dialog is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";

import * as React from "react";
import {
  Dialog,
  DialogBackdrop,
  DialogClose,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogPanel,
  DialogTitle,
  type DialogFlipDirection,
} from "@/components/ui/primitives-headless-dialog";
import { X } from "lucide-react";

type RadixDialogDemoProps = {
  from: DialogFlipDirection;
};

export const RadixDialogDemo = ({ from }: RadixDialogDemoProps) => {
  const [isOpen, setIsOpen] = React.useState(false);

  return (
    <div>
      <button
        className="bg-primary text-primary-foreground px-4 py-2 text-sm"
        onClick={() => setIsOpen(true)}
      >
        Open Dialog
      </button>

      <Dialog open={isOpen} onClose={() => setIsOpen(false)}>
        <DialogBackdrop className="fixed inset-0 z-50 bg-black/80" />
        <DialogPanel
          from={from}
          className="sm:max-w-md fixed left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] z-50 border bg-background p-6"
        >
          <DialogHeader>
            <DialogTitle className="text-lg">Terms of Service</DialogTitle>
            <DialogDescription className="text-sm">
              Please read the following terms of service carefully.
            </DialogDescription>
          </DialogHeader>

          <p className="py-4 text-sm text-muted-foreground">
            Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam,
            quos. Lorem ipsum dolor sit amet consectetur adipisicing elit.
            Quisquam, quos.
          </p>

          <DialogFooter>
            <button className="bg-primary text-primary-foreground px-4 py-2 text-sm">
              Accept
            </button>
          </DialogFooter>

          <DialogClose className="absolute top-4 right-4">
            <X className="size-4" />
            <span className="sr-only">Close</span>
          </DialogClose>
        </DialogPanel>
      </Dialog>
    </div>
  );
};

export default function DialogDemo() {
  return (
    <div className="flex h-[300px] w-full items-center justify-center">
      <RadixDialogDemo from="top" />
    </div>
  );
}

Dependencies

More by Elliot Sutton

View all
  • Notification List

    Notification List

    210
  • Scroll Progress

    Scroll Progress

    137
  • Cursor

    Cursor

    126
  • Pin List

    Pin List

    108
  • Radix Dropdown Menu

    Radix Dropdown Menu

    100
  • Flip Button

    Flip Button

    96
  • Bubble Background

    Bubble Background

    92
  • Avatar Group

    Avatar Group

    83

Explore more

Part of Animate UI — browse the full library on 21st.dev.