MC Popover
A floating panel that appears on click or trigger.
Overview
The mc-popover is a core component of the MicroClub UI library. Built on the @base-ui/react popover primitive, it combines world-class accessibility with MicroClub's signature styling via Tailwind CSS v4.
As a part of the MicroClub library, this component is designed for instant deployment into your codebase, giving you full ownership of its look and behavior.
Preview
import { McButton } from '../ui/mc-button';import { McPopover, McPopoverContent, McPopoverDescription, McPopoverHeader, McPopoverTitle, McPopoverTrigger,} from '../ui/mc-popover';const fields = [ { id: 'width', label: 'Width' }, { id: 'height', label: 'Height' }, { id: 'depth', label: 'Depth' }, { id: 'offset', label: 'Offset' },] as const;export default function McPopoverDemo() { return ( <div className="relative -top-4 py-10"> <McPopover> <McPopoverTrigger render={ <McButton variant="secondary" size="md"> Popover </McButton> } /> <McPopoverContent> <McPopoverHeader className="mb-4"> <McPopoverTitle>Dimensions</McPopoverTitle> <McPopoverDescription>Set the dimensions for the layer.</McPopoverDescription> </McPopoverHeader> <div className="flex flex-col gap-2 pl-4"> {fields.map((field) => ( <div key={field.id} className="flex items-center gap-2"> <label htmlFor={field.id} className="w-1/2 text-sm font-medium text-card-foreground" > {field.label} </label> <input id={field.id} defaultValue="100%" className="h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base text-foreground shadow-sm transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 md:text-sm" /> </div> ))} </div> </McPopoverContent> </McPopover> </div> );}Add to Your Project
Deploy the mc-popover directly to your components/ui directory:
Manual Setup
If you prefer manual control:
'use client';import * as React from 'react';import { Popover as PopoverPrimitive } from '@base-ui/react/popover';import { cn } from '@/lib/utils';function McPopover({ ...props }: PopoverPrimitive.Root.Props) { return <PopoverPrimitive.Root data-slot="popover" {...props} />;}function McPopoverTrigger({ ...props }: PopoverPrimitive.Trigger.Props) { return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;}function McPopoverContent({ className, align = 'center', alignOffset = 0, side = 'bottom', sideOffset = 23, ...props}: PopoverPrimitive.Popup.Props & Pick<PopoverPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>) { return ( <PopoverPrimitive.Portal> <PopoverPrimitive.Positioner align={align} alignOffset={alignOffset} side={side} sideOffset={sideOffset} className="isolate z-50" > <PopoverPrimitive.Popup data-slot="popover-content" className={cn( 'z-50 flex h-[268px] w-[276px] origin-(--transform-origin) flex-col gap-[13px] rounded-lg bg-card p-4 text-sm text-card-foreground shadow-sm outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95', className )} {...props} /> </PopoverPrimitive.Positioner> </PopoverPrimitive.Portal> );}function McPopoverHeader({ className, ...props }: React.ComponentProps<'div'>) { return ( <div data-slot="popover-header" className={cn('flex flex-col gap-[9px] text-sm', className)} {...props} /> );}function McPopoverTitle({ className, ...props }: PopoverPrimitive.Title.Props) { return ( <PopoverPrimitive.Title data-slot="popover-title" className={cn( 'font-plus-jakarta-sans text-left text-[20px] leading-[30px] font-medium tracking-[0] text-card-foreground', className )} {...props} /> );}function McPopoverDescription({ className, ...props }: PopoverPrimitive.Description.Props) { return ( <PopoverPrimitive.Description data-slot="popover-description" className={cn( 'font-dm-sans text-left text-[14px] leading-[20px] font-normal tracking-[0] text-muted-foreground', className )} {...props} /> );}export { McPopover, McPopoverContent, McPopoverDescription, McPopoverHeader, McPopoverTitle, McPopoverTrigger,};Add the following to your global CSS file:
@layer base {
:root {
--z-popover: 50;
/* Dimensions */
--popover-width: 276px;
--popover-height: 268px;
/* Positioning */
--popover-top: 59px;
--popover-left: 22px;
/* Appearance */
--popover-radius: var(--radius-gl);
--popover-bg: var(--Card-Background, #ffffff);
--popover-shadow: 0px 4px 12px -4px #00000014;
--popover-opacity: 1;
/* Spacing */
--popover-gap: 13px;
--popover-padding: 16px;
--popover-header-gap: 0.125rem;
/* Typography */
--popover-font-size: 0.875rem;
/* Animation */
--popover-duration: 100ms;
}
}Ensure your @/lib/utils or equivalent classname helper is correctly imported.
Usage
import {
McPopover,
McPopoverTrigger,
McPopoverContent,
McPopoverHeader,
McPopoverTitle,
McPopoverDescription,
} from '@/components/ui/mc-popover';
export default function Example() {
return (
<McPopover>
<McPopoverTrigger>Open</McPopoverTrigger>
<McPopoverContent>
<McPopoverHeader>
<McPopoverTitle>Title</McPopoverTitle>
<McPopoverDescription>Description goes here.</McPopoverDescription>
</McPopoverHeader>
</McPopoverContent>
</McPopover>
);
}Examples
Side Placement
<McPopover>
<McPopoverTrigger>Top</McPopoverTrigger>
<McPopoverContent side="top">
<McPopoverHeader>
<McPopoverTitle>Top McPopover</McPopoverTitle>
</McPopoverHeader>
</McPopoverContent>
</McPopover>
<McPopover>
<McPopoverTrigger>Right</McPopoverTrigger>
<McPopoverContent side="right">
<McPopoverHeader>
<McPopoverTitle>Right McPopover</McPopoverTitle>
</McPopoverHeader>
</McPopoverContent>
</McPopover>
<McPopover>
<McPopoverTrigger>Bottom</McPopoverTrigger>
<McPopoverContent side="bottom">
<McPopoverHeader>
<McPopoverTitle>Bottom McPopover</McPopoverTitle>
</McPopoverHeader>
</McPopoverContent>
</McPopover>
<McPopover>
<McPopoverTrigger>Left</McPopoverTrigger>
<McPopoverContent side="left">
<McPopoverHeader>
<McPopoverTitle>Left McPopover</McPopoverTitle>
</McPopoverHeader>
</McPopoverContent>
</McPopover>Alignment
<McPopover>
<McPopoverTrigger>Start</McPopoverTrigger>
<McPopoverContent align="start">
<McPopoverHeader>
<McPopoverTitle>Aligned Start</McPopoverTitle>
</McPopoverHeader>
</McPopoverContent>
</McPopover>
<McPopover>
<McPopoverTrigger>Center</McPopoverTrigger>
<McPopoverContent align="center">
<McPopoverHeader>
<McPopoverTitle>Aligned Center</McPopoverTitle>
</McPopoverHeader>
</McPopoverContent>
</McPopover>
<McPopover>
<McPopoverTrigger>End</McPopoverTrigger>
<McPopoverContent align="end">
<McPopoverHeader>
<McPopoverTitle>Aligned End</McPopoverTitle>
</McPopoverHeader>
</McPopoverContent>
</McPopover>With Custom Content
<McPopover>
<McPopoverTrigger>Settings</McPopoverTrigger>
<McPopoverContent>
<McPopoverHeader>
<McPopoverTitle>Settings</McPopoverTitle>
<McPopoverDescription>Manage your preferences.</McPopoverDescription>
</McPopoverHeader>
<div className="flex flex-col gap-2">
<McButton variant="secondary">Save Changes</McButton>
<McButton variant="tertiary">Reset</McButton>
</div>
</McPopoverContent>
</McPopover>API Reference
McPopover
The root component that manages open/close state.
| Prop | Type | Default | Description |
|---|---|---|---|
defaultOpen | boolean | false | Initial open state (uncontrolled) |
open | boolean | undefined | Controlled open state |
onOpenChange | (open: boolean) => void | undefined | Callback fired when open state changes |
McPopoverTrigger
The element that toggles the popover. Renders a <button> by default.
All props from @base-ui/react/popover Trigger are supported.
McPopoverContent
The floating panel that appears when the popover is open.
| Prop | Type | Default | Description |
|---|---|---|---|
side | "top" | "bottom" | "left" | "right" | "bottom" | Preferred side of the trigger to open on |
sideOffset | number | 4 | Distance in px from the trigger |
align | "start" | "center" | "end" | "center" | Alignment along the trigger axis |
alignOffset | number | 0 | Offset in px along the alignment axis |
className | string | undefined | Additional CSS classes |
All other props from @base-ui/react/popover Popup are supported.
McPopoverHeader
A layout wrapper for the title and description.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | undefined | Additional CSS classes |
McPopoverTitle
The accessible title of the popover.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | undefined | Additional CSS classes |
McPopoverDescription
The accessible description of the popover.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | undefined | Additional CSS classes |