- AccordionNew
- Alert
- Alert DialogNew
- AutocompleteNew
- AvatarNew
- Badge
- Breadcrumb
- Button
- CalendarNew
- CardNew
- Checkbox
- Checkbox GroupNew
- CollapsibleNew
- ComboboxNew
- CommandNew
- Context MenuNew
- Date PickerNew
- DialogNew
- DrawerNew
- EmptyNew
- FieldNew
- FieldsetNew
- FormNew
- FrameNew
- GroupNew
- Input
- Input GroupNew
- KbdNew
- Label
- MenuNew
- MeterNew
- Number Field
- OTP FieldNew
- Pagination
- PopoverNew
- Preview CardNew
- Progress
- Radio Group
- Scroll AreaNew
- Select
- Separator
- SheetNew
- SkeletonNew
- Slider
- Spinner
- StepperNew
- Switch
- Table
- TabsNew
- Textarea
- ToastNew
- ToggleNew
- Toggle GroupNew
- ToolbarNew
- Tooltip
Popover
An accessible popup anchored to a button.
"use client";
import { Button } from "mako-ui/components/button";
import { Field } from "mako-ui/components/field";
import { Form } from "mako-ui/components/form";
import {
Popover,
PopoverDescription,
PopoverPopup,
PopoverTitle,
PopoverTrigger,
} from "mako-ui/components/popover";
import { Textarea } from "mako-ui/components/textarea";
export default function Particle() {
return (
<Popover>
<PopoverTrigger render={<Button variant="outline" />}>
Open Popover
</PopoverTrigger>
<PopoverPopup className="w-80">
<div className="mb-4">
<PopoverTitle className="text-base">Send us feedback</PopoverTitle>
<PopoverDescription>
Let us know how we can improve.
</PopoverDescription>
</div>
<Form className="flex w-full flex-col gap-4">
<Field>
<Textarea
aria-label="Send feedback"
id="feedback"
placeholder="How can we improve?"
/>
</Field>
<Button type="submit">Send feedback</Button>
</Form>
</PopoverPopup>
</Popover>
);
}
Usage
import {
Popover,
PopoverClose,
PopoverDescription,
PopoverPopup,
PopoverTitle,
PopoverTrigger,
} from "mako-ui/components/popover"<Popover>
<PopoverTrigger>Open Popover</PopoverTrigger>
<PopoverPopup>
<PopoverTitle>Popover Title</PopoverTitle>
<PopoverDescription>Popover Description</PopoverDescription>
<PopoverClose>Close</PopoverClose>
</PopoverPopup>
</Popover>API Reference
Popover
Root component.
PopoverTrigger
Trigger button that opens the popover.
PopoverPopup
Popup container that displays the popover content. Also exported as PopoverContent.
| Prop | Type | Default | Description |
|---|---|---|---|
tooltipStyle | boolean | false | When true, applies tooltip-like styling (smaller padding, arrow) |
side | "top" | "bottom" | "left" | "right" | "bottom" | Side of the trigger to position the popup |
align | "start" | "center" | "end" | "center" | Alignment relative to the trigger |
sideOffset | number | 4 | Distance from the trigger in pixels |
alignOffset | number | 0 | Offset along the alignment axis |
portalProps | PortalProps | - | Props forwarded to the internal portal (keepMounted, container, etc.) |
PopoverTitle
Title text for the popover.
PopoverDescription
Description text for the popover.
PopoverClose
Close button for the popover.
PopoverCreateHandle
Creates a handle for detached popover triggers. Returns a handle object to attach to multiple triggers.
Examples
With Close Button
"use client";
import { Button } from "mako-ui/components/button";
import {
Popover,
PopoverClose,
PopoverDescription,
PopoverPopup,
PopoverTitle,
PopoverTrigger,
} from "mako-ui/components/popover";
import { Cross } from "mako-ui/icons/cross";
export default function Particle() {
return (
<Popover>
<PopoverTrigger render={<Button variant="outline" />}>
Open Popover
</PopoverTrigger>
<PopoverPopup className="w-80">
<PopoverClose
aria-label="Close"
className="absolute inset-e-2 top-2"
render={<Button size="icon" variant="ghost" />}
>
<Cross />
</PopoverClose>
<div className="mb-2">
<PopoverTitle className="text-base">Notifications</PopoverTitle>
<PopoverDescription>
You are all caught up. Good job!
</PopoverDescription>
</div>
<PopoverClose render={<Button variant="outline" />}>Close</PopoverClose>
</PopoverPopup>
</Popover>
);
}
Tooltip Style
Use the tooltipStyle prop to make a popover look like a tooltip. This is recommended when you have an info icon button whose only purpose is to show additional information. See the tooltip accessibility guidelines for best practices.
"use client";
import { Button } from "mako-ui/components/button";
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
} from "mako-ui/components/input-group";
import {
Popover,
PopoverPopup,
PopoverTrigger,
} from "mako-ui/components/popover";
import { Informational } from "mako-ui/icons/informational";
export default function Particle() {
return (
<InputGroup>
<InputGroupInput
aria-label="Password"
placeholder="Password"
type="password"
/>
<InputGroupAddon align="inline-end">
<Popover>
<PopoverTrigger
openOnHover
render={
<Button
aria-label="Password requirements"
size="icon-xs"
variant="ghost"
/>
}
>
<Informational />
</PopoverTrigger>
<PopoverPopup side="top" tooltipStyle>
<p>Min. 8 characters</p>
</PopoverPopup>
</Popover>
</InputGroupAddon>
</InputGroup>
);
}
Animated Popovers
You can create animated popovers that smoothly transition between different triggers using detached triggers. This pattern allows multiple triggers to share a single popover popup, with automatic animations for position, size, and content changes.
To create detached triggers:
- Create a handle using
PopoverCreateHandle - Attach the same handle to multiple
PopoverTriggercomponents - Each trigger provides a
payloadprop containing the content component - Use a single
Popovercomponent with the handle to render the popup
"use client";
import { Avatar, AvatarFallback, AvatarImage } from "mako-ui/components/avatar";
import { Button } from "mako-ui/components/button";
import {
Popover,
PopoverCreateHandle,
PopoverDescription,
PopoverPopup,
PopoverTitle,
PopoverTrigger,
} from "mako-ui/components/popover";
import { Notification } from "mako-ui/icons/notification";
import { User } from "mako-ui/icons/user";
import type { ComponentType } from "react";
const popoverHandle = PopoverCreateHandle<ComponentType>();
const NotificationsContent = () => {
return (
<>
<PopoverTitle className="text-base">Notifications</PopoverTitle>
<PopoverDescription>
You have no new notifications at this time.
</PopoverDescription>
</>
);
};
const ProfileContent = () => {
return (
<div className="w-48">
<div className="flex items-center gap-3">
<Avatar>
<AvatarImage alt="Mark Andersson" src="/images/portrait-1.jpg" />
<AvatarFallback>MA</AvatarFallback>
</Avatar>
<div className="min-w-0 flex-1">
<h4 className="line-clamp-1 font-medium text-sm">Mark Andersson</h4>
<div className="flex items-center gap-3 text-muted-foreground text-xs">
Product Designer
</div>
</div>
</div>
<Button className="mt-3 w-full" size="sm" variant="outline">
Log out
</Button>
</div>
);
};
export default function Particle() {
return (
<div className="flex gap-2">
<PopoverTrigger
handle={popoverHandle}
payload={NotificationsContent}
render={
<Button aria-label="Notifications" size="icon" variant="outline" />
}
>
<Notification aria-hidden="true" />
</PopoverTrigger>
<PopoverTrigger
handle={popoverHandle}
payload={ProfileContent}
render={<Button aria-label="Profile" size="icon" variant="outline" />}
>
<User aria-hidden="true" />
</PopoverTrigger>
<Popover handle={popoverHandle}>
{({ payload: Payload }) => (
<PopoverPopup className="min-w-none">
{Payload !== undefined && <Payload />}
</PopoverPopup>
)}
</Popover>
</div>
);
}