Componentpopover
Popover
Displays rich content in a portal, triggered by a button.
Preview
Displays rich content in a portal, triggered by a button.
@ui.Popover(ui.PopoverProps{}) {
@ui.PopoverTrigger(ui.DOMProps{}) {
@ui.Button(ui.ButtonProps{Variant: ui.ButtonVariantOutline}) { Open popover }
}
@ui.PopoverContent(ui.DOMProps{Class: "w-80"}) {
<div class="grid gap-4">
<div class="space-y-2">
<h4 class="font-medium leading-none">Dimensions</h4>
<p class="text-sm text-muted-foreground">Set the dimensions for the layer.</p>
</div>
</div>
}
}Installation
Add this component to your project using the CLI.
templcn add popoverUsage
1. Import the component in your Go or templ file:
import "your-module/ui"2. Use the component in your template:
@ui.Popover(ui.PopoverProps{}) {
@ui.PopoverTrigger(ui.DOMProps{}) {
@ui.Button(ui.ButtonProps{Variant: ui.ButtonVariantOutline}) { Open popover }
}
@ui.PopoverContent(ui.DOMProps{Class: "w-80"}) {
<div class="grid gap-4">
<div class="space-y-2">
<h4 class="font-medium leading-none">Dimensions</h4>
<p class="text-sm text-muted-foreground">Set the dimensions for the layer.</p>
</div>
</div>
}
}Composition
Use these parts together to build the component.
Popover
├── PopoverTrigger
├── Button
├── PopoverContentExamples
Named examples and common variations.
Default
Anchored popover panel with custom content.
Popover content
@ui.Popover(ui.PopoverProps{}) {
@ui.PopoverTrigger(ui.DOMProps{}) { Open }
@ui.PopoverContent(ui.DOMProps{}) { Popover content }
}API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| Side | string | "bottom" | Preferred placement side. |
| Align | string | "center" | Alignment along the axis. |
| Modal | bool | false | Whether to trap focus. |
View source
package ui
import (
"context"
"io"
"github.com/a-h/templ"
)
type PopoverProps struct {
DOMProps
Open bool
DefaultOpen bool
Side string
Align string
SideOffset string
AlignOffset string
Modal bool
}
func Popover(props PopoverProps) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
open := props.Open || props.DefaultOpen
attrs := attrsFromDOMProps(props.DOMProps, "popover", "relative inline-block")
attrs["data-state"] = openState(open)
if open {
attrs["data-open"] = "true"
}
if props.DefaultOpen {
attrs["data-default-open"] = "true"
}
if props.Side != "" {
attrs["data-side"] = props.Side
}
if props.Align != "" {
attrs["data-align"] = props.Align
}
if props.SideOffset != "" {
attrs["data-side-offset"] = props.SideOffset
}
if props.AlignOffset != "" {
attrs["data-align-offset"] = props.AlignOffset
}
if props.Modal {
attrs["data-modal"] = "true"
}
ctx = context.WithValue(ctx, floatingRenderStateKey{}, floatingRenderState{open: open})
return renderElement(ctx, w, "div", attrs, templ.GetChildren(ctx))
})
}
func PopoverTrigger(props DOMProps) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
attrs := attrsFromDOMProps(props, "popover-trigger", "")
if _, ok := attrs["type"]; !ok {
attrs["type"] = "button"
}
if _, ok := attrs["aria-haspopup"]; !ok {
attrs["aria-haspopup"] = "dialog"
}
if _, ok := attrs["aria-expanded"]; !ok {
attrs["aria-expanded"] = "false"
}
return renderElement(ctx, w, "button", attrs, templ.GetChildren(ctx))
})
}
func PopoverAnchor(props DOMProps) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
return renderElement(ctx, w, "div", attrsFromDOMProps(props, "popover-anchor", ""), templ.GetChildren(ctx))
})
}
func PopoverContent(props DOMProps) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
attrs := attrsFromDOMProps(props, "popover-content", "absolute left-0 top-full z-50 mt-1 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[side=bottom]:slide-in-from-top-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-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95")
if _, ok := attrs["data-state"]; !ok {
attrs["data-state"] = floatingStateFromContext(ctx)
}
if _, ok := attrs["data-side"]; !ok {
attrs["data-side"] = "bottom"
}
if _, ok := attrs["tabindex"]; !ok {
attrs["tabindex"] = "-1"
}
if !floatingOpenFromContext(ctx) {
attrs["hidden"] = true
}
return renderElement(ctx, w, "div", attrs, templ.GetChildren(ctx))
})
}
func PopoverHeader(props DOMProps) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
return renderElement(ctx, w, "div", attrsFromDOMProps(props, "popover-header", "flex flex-col gap-1 text-sm"), templ.GetChildren(ctx))
})
}
func PopoverTitle(props DOMProps) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
return renderElement(ctx, w, "div", attrsFromDOMProps(props, "popover-title", "font-medium"), templ.GetChildren(ctx))
})
}
func PopoverDescription(props DOMProps) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, w io.Writer) error {
return renderElement(ctx, w, "p", attrsFromDOMProps(props, "popover-description", "text-muted-foreground"), templ.GetChildren(ctx))
})
}