Popover

Preview

import { Button } from "@/registry/components/button/react/button";
import { Input } from "@/registry/components/input/react/input";
import { Label } from "@/registry/components/label/react/label";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/registry/components/popover/react/popover";
import type { CSSProperties } from "react";
export function PopoverDemo() {
return (
<Popover>
<PopoverTrigger asChild>
<Button data-variant="outline">Open popover</Button>
</PopoverTrigger>
<PopoverContent>
<div className="grid gap-sm" style={{ maxWidth: "20rem" } as CSSProperties}>
<div className="flow">
<h4 className="text-base font-weight-medium">Dimensions</h4>
<p className="text-sm text-muted flow-space-3xs">
Set the dimensions for the layer. Set the dimensions for the layer.
</p>
</div>
<div className="grid gap-2xs">
<div className="grid grid-cols-2 align-center">
<Label htmlFor="width">Width</Label>
<Input
id="width"
defaultValue="100%"
style={{ "--input-height": "32px" } as CSSProperties}
className="mt-0"
/>
</div>
<div className="grid grid-cols-2 align-center">
<Label htmlFor="maxWidth">Max. width</Label>
<Input
id="maxWidth"
className="mt-0"
defaultValue="300px"
style={{ "--input-height": "32px" } as CSSProperties}
/>
</div>
<div className="grid grid-cols-2 align-center">
<Label htmlFor="height">Height</Label>
<Input
id="height"
className="mt-0"
defaultValue="25px"
style={{ "--input-height": "32px" } as CSSProperties}
/>
</div>
<div className="grid grid-cols-2 align-center">
<Label htmlFor="maxHeight">Max. height</Label>
<Input
id="maxHeight"
className="mt-0"
defaultValue="none"
style={{ "--input-height": "32px" } as CSSProperties}
/>
</div>
</div>
</div>
</PopoverContent>
</Popover>
);
}

Installation

You can add the popover component in two ways:

  1. During project initialization:
pnpm dlx make-sugarcube@latest init
npx make-sugarcube@latest init
yarn make-sugarcube@latest init
bunx --bun make-sugarcube@latest init

Then select the popover component when prompted.

  1. After initialization:
pnpm dlx make-sugarcube@latest components popover --framework react
npx make-sugarcube@latest components popover --framework react
yarn make-sugarcube@latest components popover --framework react
bunx --bun make-sugarcube@latest components popover --framework react

What’s included

When you add the button component, you get:

  • popover.tsx - The React component implementation
  • popover.css - The base styles for the popover
  • @clsx - The clsx utility for conditional classes
import * as PopoverPrimitive from "@radix-ui/react-popover";
import cn from "clsx";
function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>) {
return <PopoverPrimitive.Root data-slot="popover" {...props} />;
}
function PopoverTrigger({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
}
function PopoverContent({
className,
align = "center",
sideOffset = 4,
...props
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
return (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
data-slot="popover-content"
align={align}
sideOffset={sideOffset}
className={cn("popover-content", className)}
{...props}
/>
</PopoverPrimitive.Portal>
);
}
function PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
}
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
.popover-content:has(.command) {
padding: 0;
border: none;
}
.popover-content {
outline: none;
min-width: fit-content;
background-color: var(--popover-bg);
transform-origin: var(--radix-popover-content-transform-origin);
width: var(--radix-popover-trigger-width);
border-radius: var(--popover-radius);
border-style: var(--popover-border-style);
border-width: var(--popover-border-width);
border-color: var(--popover-border-color);
padding-inline: var(--popover-padding-inline);
padding-block: var(--popover-padding-block);
box-shadow: var(--popover-shadow);
}
[data-slot="popover-trigger"] {
justify-content: space-between;
width: var(--popover-trigger-width, auto);
border-radius: var(--popover-trigger-radius);
}
.popover-content[data-state="open"] {
animation: popover-slide-in-from-top var(--duration-150) var(--ease-out);
}
.popover-content[data-side="bottom"] {
animation: popover-slide-in-from-top var(--duration-150) var(--ease-out);
}
.popover-content[data-side="left"] {
animation: popover-slide-in-from-right var(--duration-150) var(--ease-out);
}
.popover-content[data-side="right"] {
animation: popover-slide-in-from-left var(--duration-150) var(--ease-out);
}
.popover-content[data-side="top"] {
animation: popover-slide-in-from-bottom var(--duration-150) var(--ease-out);
}
@keyframes popover-slide-in-from-top {
from {
opacity: 0;
transform: translateY(-8px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
@keyframes popover-slide-in-from-bottom {
from {
opacity: 0;
transform: translateY(8px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
@keyframes popover-slide-in-from-left {
from {
opacity: 0;
transform: translateX(-8px) scale(0.95);
}
to {
opacity: 1;
transform: translateX(0) scale(1);
}
}
@keyframes popover-slide-in-from-right {
from {
opacity: 0;
transform: translateX(8px) scale(0.95);
}
to {
opacity: 1;
transform: translateX(0) scale(1);
}
}

Examples

:::note The following examples show how to use data attributes for variants. This is just one possible approach. See the principles section for more information on how to approach component variants. :::