PRIZM 4.0DSTA
All components

Popover

Floating contextual panel.

stableBase UI Popover

Preview

Code

tsx
import { Button } from "@/components/ui/button";
import {
  Popover, PopoverContent, PopoverDescription,
  PopoverHeader, PopoverTitle, PopoverTrigger,
} from "@/components/ui/popover";

export function Example() {
  return (
    <Popover>
      <PopoverTrigger render={<Button variant="outline">Open popover</Button>} />
      <PopoverContent>
        <PopoverHeader>
          <PopoverTitle>Settings</PopoverTitle>
          <PopoverDescription>Manage your notification preferences.</PopoverDescription>
        </PopoverHeader>
      </PopoverContent>
    </Popover>
  );
}

Props

PropTypeDefaultDescription
openbooleanControlled open state.
defaultOpenbooleanUncontrolled initial open state.
onOpenChange(open: boolean) => voidCalled when the open state changes.

Sub-components

PopoverTriggerElement that opens the popover. Supports `render` for asChild.
PopoverContentThe floating popup. Portals to body.
PropTypeDefaultDescription
sideOffsetnumber8Pixel gap between trigger and popover.
variant"solid" | "glass""solid"Surface treatment. glass (C3 only) for floating over canvas content.
showCloseButtonbooleanfalseRender an X close button.
PopoverHeaderTop section with title + description.
PopoverTitleWired to `aria-labelledby`.
PopoverDescriptionWired to `aria-describedby`.

Built on Base UI Popover.

All components also accept standard HTML attributes for their root element (e.g. `id`, `aria-*`, `data-*`, event handlers) and forward `ref` where applicable.

Source

The full implementation of components/ui/popover.tsx is below — copy it into your project and own it. Some components import the cn helper from lib/utils or other primitives; copy those too.

tsx
"use client";

import { cn } from "@/lib/utils";
import { Popover as BasePopover } from "@base-ui-components/react/popover";
import { X } from "lucide-react";
import type { ComponentPropsWithoutRef, ReactNode } from "react";

export const Popover = BasePopover.Root;
export const PopoverTrigger = BasePopover.Trigger;
export const PopoverClose = BasePopover.Close;

export function PopoverContent({
  className,
  children,
  sideOffset = 8,
  variant = "solid",
  showCloseButton = false,
  ...props
}: ComponentPropsWithoutRef<typeof BasePopover.Popup> & {
  sideOffset?: number;
  variant?: "solid" | "glass";
  showCloseButton?: boolean;
  children?: ReactNode;
}) {
  return (
    <BasePopover.Portal>
      <BasePopover.Positioner sideOffset={sideOffset}>
        <BasePopover.Popup
          className={cn(
            "z-50 w-72 rounded-lg border border-border p-4 shadow-md",
            variant === "glass" ? "surface-glass-panel" : "bg-surface-elevated",
            "data-[starting-style]:opacity-0 data-[starting-style]:scale-95",
            "data-[ending-style]:opacity-0 data-[ending-style]:scale-95",
            "transition-all duration-150",
            className,
          )}
          {...props}
        >
          {children}
          {showCloseButton && (
            <BasePopover.Close
              className={cn(
                "absolute right-3 top-3 rounded-sm text-fg-muted opacity-70 transition-opacity",
                "hover:opacity-100 focus-visible:outline-1 focus-visible:outline-offset-0 focus-visible:outline-accent",
              )}
              aria-label="Close"
            >
              <X className="h-4 w-4" />
            </BasePopover.Close>
          )}
        </BasePopover.Popup>
      </BasePopover.Positioner>
    </BasePopover.Portal>
  );
}

export function PopoverHeader({ className, ...props }: ComponentPropsWithoutRef<"div">) {
  return <div className={cn("mb-2 flex flex-col gap-1", className)} {...props} />;
}

export function PopoverTitle({
  className,
  ...props
}: ComponentPropsWithoutRef<typeof BasePopover.Title>) {
  return (
    <BasePopover.Title className={cn("text-sm font-semibold text-fg", className)} {...props} />
  );
}

export function PopoverDescription({
  className,
  ...props
}: ComponentPropsWithoutRef<typeof BasePopover.Description>) {
  return <BasePopover.Description className={cn("text-sm text-fg-muted", className)} {...props} />;
}

JavaFX

Ships in the PRIZM JavaFX library for thick-client C3 apps as PrizmPopover (extends PopupControl). Run the gallery to see it natively.

java
import design.prizm.fx.controls.PrizmPopover;

PrizmPopover()
PrizmPopover(Node content)
PropTypeDefaultDescription
setContent(Node) → voidThe body; compose it yourself (e.g. a VBox of labels).
show(Node owner) → voidShow anchored below the owner; auto-fixes on-screen. Inherited show(owner, x, y) for custom placement.

Built on PopupControl, so its content inherits the owner scene's PRIZM theme (like Tooltip / ContextMenu). Auto-hides on focus loss, styled by the .prizm-popover rules. The web `glass` variant is NOT ported. Mirrors components/ui/popover.tsx.