Popover
HeroUIRich content beside a trigger, HeroUI's on Kobalte's.
Solidtype_heroui.Popover is Kobalte’s Popover, with the classes HeroUI’s
own popoverVariants gives and HeroUI’s arrow. A Button inside it is its
trigger, as in HeroUI; anything else is wrapped in Popover.Trigger.
module Button = Solidtype_heroui.Buttonmodule Popover = Solidtype_heroui.Popover
let make () = <div class_="flex items-center gap-4"> <Popover> <Button>"Click me"</Button> <Popover.Content class_="max-w-64"> <Popover.Dialog> <Popover.Heading>"Popover Title"</Popover.Heading> <p class_="mt-2 text-sm text-muted"> "This is the popover content. You can put any content here." </p> </Popover.Dialog> </Popover.Content> </Popover> </div>Anatomy
Section titled “Anatomy”<Popover> <Popover.Trigger>...</Popover.Trigger> <Popover.Content> <Popover.Arrow /> <Popover.Dialog> <Popover.Heading>...</Popover.Heading> ... </Popover.Dialog> </Popover.Content></Popover>Examples
Section titled “Examples”With Arrow
Section titled “With Arrow”module Button = Solidtype_heroui.Buttonmodule Popover = Solidtype_heroui.Popover
let make () = <div class_="flex items-center gap-4"> <Popover> <Button variant=`secondary>"With Arrow"</Button> <Popover.Content class_="max-w-64"> <Popover.Dialog> <Popover.Arrow /> <Popover.Heading>"Popover with Arrow"</Popover.Heading> <p class_="mt-2 text-sm text-muted"> "The arrow shows which element triggered the popover." </p> </Popover.Dialog> </Popover.Content> </Popover> <Popover> <Button is_icon_only=true aria_label="More options" variant=`tertiary> <Gravity.Ellipsis /> </Button> <Popover.Content class_="max-w-64" offset=10.> <Popover.Dialog> <Popover.Arrow /> <Popover.Heading>"Popover with Arrow"</Popover.Heading> <p class_="mt-2 text-sm text-muted"> "The arrow shows which element triggered the popover." </p> </Popover.Dialog> </Popover.Content> </Popover> </div>Interactive Content
Section titled “Interactive Content”Sarah Johnson
@sarahj
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Avatar = Solidtype_heroui.Avatarmodule Button = Solidtype_heroui.Buttonmodule Popover = Solidtype_heroui.Popover
let make () = let following, set_following = S.create_signal false in <div class_="flex items-center gap-6"> <Popover> <Popover.Trigger aria_label="User profile"> <div class_="flex items-center gap-2"> <Avatar size=`sm> <Avatar.Image alt="Sarah Johnson" src="https://img.heroui.chat/image/avatar?w=400&h=400&u=1" /> <Avatar.Fallback>"SJ"</Avatar.Fallback> </Avatar> <div class_="flex flex-col"> <p class_="text-sm font-medium">"Sarah Johnson"</p> <p class_="text-xs text-muted">"@sarahj"</p> </div> </div> </Popover.Trigger> <Popover.Content class_="w-[320px]"> <Popover.Dialog> <Popover.Heading> <div class_="flex items-center justify-between"> <div class_="flex items-center gap-3"> <Avatar size=`md> <Avatar.Image alt="Sarah Johnson" src="https://img.heroui.chat/image/avatar?w=400&h=400&u=1" /> <Avatar.Fallback>"SJ"</Avatar.Fallback> </Avatar> <div> <p class_="font-semibold">"Sarah Johnson"</p> <p class_="text-sm text-muted">"@sarahj"</p> </div> </div> <Button class_="rounded-full" size=`sm variant=(fun () -> if S.get following then `tertiary else `primary) on_click=(fun _ -> S.update set_following not)> (fun () -> Jsx.string (if S.get following then "Following" else "Follow")) </Button> </div> </Popover.Heading> <p class_="mt-3 text-sm text-muted"> "Product designer and creative director. Building beautiful \ experiences that matter." </p> <div class_="mt-3 flex gap-4"> <div> <span class_="font-semibold">"892"</span> <span class_="ms-1 text-sm text-muted">"Following"</span> </div> <div> <span class_="font-semibold">"12.5K"</span> <span class_="ms-1 text-sm text-muted">"Followers"</span> </div> </div> </Popover.Dialog> </Popover.Content> </Popover> </div>Placement
Section titled “Placement”module Button = Solidtype_heroui.Buttonmodule Popover = Solidtype_heroui.Popover
let make () = <div class_="grid grid-cols-3 gap-4"> <div /> <Popover> <Button class_="w-full" variant=`tertiary>"Top"</Button> <Popover.Content placement=`top> <Popover.Dialog> <Popover.Arrow /> <p class_="text-sm">"Top placement"</p> </Popover.Dialog> </Popover.Content> </Popover> <div /> <Popover> <Button class_="w-full" variant=`tertiary>"Left"</Button> <Popover.Content placement=`left> <Popover.Dialog> <Popover.Arrow /> <p class_="text-sm">"Left placement"</p> </Popover.Dialog> </Popover.Content> </Popover> <div class_="flex items-center justify-center"> <span class_="text-sm text-muted">"Click buttons"</span> </div> <Popover> <Button class_="w-full" variant=`tertiary>"Right"</Button> <Popover.Content placement=`right> <Popover.Dialog> <Popover.Arrow /> <p class_="text-sm">"Right placement"</p> </Popover.Dialog> </Popover.Content> </Popover> <div /> <Popover> <Button class_="w-full" variant=`tertiary>"Bottom"</Button> <Popover.Content placement=`bottom> <Popover.Dialog> <Popover.Arrow /> <p class_="text-sm">"Bottom placement"</p> </Popover.Dialog> </Popover.Content> </Popover> <div /> </div>Render Function
Section titled “Render Function”HeroUI’s Render Function example gives the content render, React’s way to
swap the element it renders, which a Solid component has no need of.
Customization
Section titled “Customization”Tailwind CSS
Section titled “Tailwind CSS”class_ is added after HeroUI’s classes.
module Button = Solidtype_heroui.Buttonmodule Popover = Solidtype_heroui.Popover
let make () = <Popover> <Button variant=`secondary>"Details"</Button> <Popover.Content class_="max-w-56 overflow-hidden rounded-xl border border-border/80 \ bg-surface/90 p-0 shadow-xl ring-1 ring-black/5 backdrop-blur-xl \ dark:border-border/90 dark:bg-surface/85 dark:ring-white/10"> <Popover.Dialog class_="relative p-4"> <div aria_hidden=true class_="pointer-events-none absolute inset-x-0 top-0 h-12 \ bg-linear-to-b from-neutral-500/6 to-transparent \ dark:from-neutral-400/8" /> <Popover.Heading class_="relative font-medium text-neutral-800 dark:text-neutral-100"> "Keyboard shortcuts" </Popover.Heading> <dl class_="relative mt-3 space-y-2 text-sm"> <div class_="flex justify-between gap-4"> <dt class_="text-muted">"Save"</dt> <dd class_="font-mono text-neutral-700 dark:text-neutral-300"> {js|⌘ S|js} </dd> </div> <div class_="flex justify-between gap-4"> <dt class_="text-muted">"Search"</dt> <dd class_="font-mono text-neutral-700 dark:text-neutral-300"> {js|⌘ K|js} </dd> </div> </dl> </Popover.Dialog> </Popover.Content> </Popover>Global CSS
Section titled “Global CSS”HeroUI’s classes are global, so a stylesheet restyles every one, as with HeroUI in React:
@layer components { .popover { @apply rounded-xl shadow-2xl; }
.popover__dialog { @apply p-4; }
.popover__heading { @apply text-lg font-bold; }}Styling Reference
Section titled “Styling Reference”CSS Classes
Section titled “CSS Classes”.popover,.popover__dialog,.popover__heading,.popover__trigger
Interactive States
Section titled “Interactive States”- Entering:
[data-entering="true"], while it appears - Exiting:
[data-exiting="true"], while it disappears - Placement:
[data-placement="bottom"], and the other sides - Focus:
:focus-visibleor[data-focus-visible="true"]on a trigger
How it is made
Section titled “How it is made”Kobalte’s popover opens, closes, places itself, keeps the focus inside it
and hides the page outside from a reader while it is open, as React Aria’s
does. The port gives the focus to its dialog as it opens, as React Aria’s
does, where Kobalte’s gives it to the first button inside, and back to its
trigger as it closes. Its trigger shows pressed while it is open, as HeroUI’s
does, and a button inside it is a button, not a second trigger. Either side
of it is a dismiss button only a reader finds, as React Aria puts one; here
it is a type="button", so a popover inside a form does not submit it.
Kobalte’s content is the dialog, named by its heading, where React Aria’s is
the section inside it; a reader is told the same. Its arrow is drawn as
Tooltip’s is: Kobalte’s, hidden, places HeroUI’s.
API Reference
Section titled “API Reference”Each prop beside the name HeroUI’s React component gives it.
Popover
Section titled “Popover”| React | solidtype | Type | Default | Description |
|---|---|---|---|---|
isOpen |
is_open |
bool |
Whether it is open, controlled | |
defaultOpen |
default_open |
bool |
false |
Whether it starts open |
onOpenChange |
on_open_change |
bool -> unit |
Told as it opens or closes | |
children |
children |
elements | Its trigger and its content |
Popover.Content
Section titled “Popover.Content”| React | solidtype | Type | Default | Description |
|---|---|---|---|---|
placement |
placement |
`top | `bottom | `left | `right |
`bottom |
Its side of the trigger |
offset |
offset |
float |
8 | Its distance from the trigger |
shouldFlip |
should_flip |
bool |
true |
Whether it moves to the other side where there is no room |
className |
class_ |
string |
Added after HeroUI’s classes | |
children |
children |
elements | What it shows |
Popover.Dialog, Popover.Heading
Section titled “Popover.Dialog, Popover.Heading”| React | solidtype | Type | Description |
|---|---|---|---|
className |
class_ |
string |
Added after HeroUI’s classes |
children |
children |
elements | What it holds |
Popover.Trigger
Section titled “Popover.Trigger”| React | solidtype | Type | Description |
|---|---|---|---|
aria-label |
aria_label |
string |
Its name, where its children give none |
className |
class_ |
string |
Added after HeroUI’s classes |
children |
children |
elements | What it wraps |
Popover.Arrow
Section titled “Popover.Arrow”| React | solidtype | Type | Description |
|---|---|---|---|
className |
class_ |
string |
Its class |
children |
children |
elements | An arrow of its own, in place of HeroUI’s |
Beside React
Section titled “Beside React”Original HeroUI documentation: Popover.
The same HeroUI Popover twice, under the same props: in solidtype on the left, in React on the right. Below them, every attribute of each trigger: a marked row is one they disagree on, and a dimmed row is a framework’s own, which no style reads.
| attribute | solidtype | React |
|---|
