Works natively with Cursor. Add npx -y bare-ui-mcp to your MCP settings.

Native Modal

Built on the native HTML dialog element for performance and accessibility.

Interactive Modal

This modal is built with zero dependencies using the native <dialog> element. It automatically handles focus trapping and Esc key to close!

Installation

1. Copy the React component into your project:

tsx
"use client";

import { ReactNode, useEffect, useRef } from "react";

interface ModalProps {
  isOpen: boolean;
  onClose: () => void;
  title?: string;
  children: ReactNode;
}

/**
 * A lightweight modal component using the native HTML <dialog> element.
 */
export const Modal = ({ isOpen, onClose, title, children }: ModalProps) => {
  const dialogRef = useRef<HTMLDialogElement>(null);

  useEffect(() => {
    const dialog = dialogRef.current;
    if (!dialog) return;

    if (isOpen) {
      if (!dialog.open) {
        dialog.showModal();
      }
    } else {
      if (dialog.open) {
        dialog.close();
      }
    }
  }, [isOpen]);

  const handleBackdropClick = (e: React.MouseEvent) => {
    if (e.target === dialogRef.current) {
      onClose();
    }
  };

  return (
    <dialog
      ref={dialogRef}
      onClose={onClose}
      onClick={handleBackdropClick}
      style={{
        padding: 0,
        border: "none",
        borderRadius: "1rem",
        background: "var(--bg-primary)",
        color: "var(--text-primary)",
        boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
        maxWidth: "500px",
        width: "90%",
        margin: "auto",
      }}
    >
      <div style={{ padding: "1.5rem" }}>
        <div
          style={{
            display: "flex",
            justifyContent: "space-between",
            alignItems: "center",
            marginBottom: "1.5rem",
            borderBottom: "1px solid var(--border-color)",
            paddingBottom: "1rem",
          }}
        >
          {title && (
            <h2 style={{ fontSize: "1.25rem", fontWeight: 700 }}>{title}</h2>
          )}
          <button
            onClick={onClose}
            aria-label="Close modal"
            style={{
              background: "none",
              border: "none",
              cursor: "pointer",
              fontSize: "1.5rem",
              color: "var(--text-muted)",
              display: "flex",
              padding: "0.25rem",
            }}
          >
            &times;
          </button>
        </div>
        <div>{children}</div>
      </div>
      <style>{`
        dialog::backdrop {
          background: rgba(0, 0, 0, 0.5);
          backdrop-filter: blur(4px);
        }
        dialog[open] {
          animation: modal-fade-in 0.3s ease-out;
        }
        @keyframes modal-fade-in {
          from { opacity: 0; transform: translateY(-20px); }
          to { opacity: 1; transform: translateY(0); }
        }
      `}</style>
    </dialog>
  );
};

Usage

tsx
import { useState } from 'react';
import { Modal } from '@/components/ui/modal';
import { Button } from '@/components/ui/button';

export default function MyComponent() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Button onClick={() => setIsOpen(true)}>Open</Button>

      <Modal isOpen={isOpen} onClose={() => setIsOpen(false)} title="Settings">
        <p>Your settings go here.</p>
      </Modal>
    </>
  );
}