Displays rich content in a portal, triggered by a button.
import type { PopoverTriggerProps } from "@kobalte/core/popover"; import { Button } from "@repo/tailwindcss/ui/button"; import { Popover, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger, } from "@repo/tailwindcss/ui/popover"; import { TextField, TextFieldLabel, TextFieldRoot, } from "@repo/tailwindcss/ui/textfield"; const PopoverDemo = () => { return ( <Popover> <PopoverTrigger as={(props: PopoverTriggerProps) => ( <Button variant="outline" {...props}> Open popover </Button> )} /> <PopoverContent class="w-80"> <div class="grid gap-4"> <PopoverTitle 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> </PopoverTitle> <PopoverDescription class="grid gap-2"> <TextFieldRoot class="grid grid-cols-3 items-center gap-4"> <TextFieldLabel class="text-right">Width</TextFieldLabel> <TextField value="100%" class="col-span-2 h-8" /> </TextFieldRoot> <TextFieldRoot class="grid grid-cols-3 items-center gap-4"> <TextFieldLabel class="text-right">Max. width</TextFieldLabel> <TextField value="300px" class="col-span-2 h-8" /> </TextFieldRoot> <TextFieldRoot class="grid grid-cols-3 items-center gap-4"> <TextFieldLabel class="text-right">Height</TextFieldLabel> <TextField value="25px" class="col-span-2 h-8" /> </TextFieldRoot> <TextFieldRoot class="grid grid-cols-3 items-center gap-4"> <TextFieldLabel class="text-right">Max. height</TextFieldLabel> <TextField value="none" class="col-span-2 h-8" /> </TextFieldRoot> </PopoverDescription> </div> </PopoverContent> </Popover> ); }; export default PopoverDemo;
npx shadcn-solid@latest add popover
npm install @kobalte/core
import { cn } from "@/libs/cn"; import type { PolymorphicProps } from "@kobalte/core/polymorphic"; import type { PopoverContentProps, PopoverRootProps, } from "@kobalte/core/popover"; import { Popover as PopoverPrimitive } from "@kobalte/core/popover"; import type { ParentProps, ValidComponent } from "solid-js"; import { mergeProps, splitProps } from "solid-js"; export const PopoverTrigger = PopoverPrimitive.Trigger; export const PopoverTitle = PopoverPrimitive.Title; export const PopoverDescription = PopoverPrimitive.Description; export const Popover = (props: PopoverRootProps) => { const merge = mergeProps<PopoverRootProps[]>( { gutter: 4, flip: false, }, props, ); return <PopoverPrimitive {...merge} />; }; type popoverContentProps<T extends ValidComponent = "div"> = ParentProps< PopoverContentProps<T> & { class?: string; } >; export const PopoverContent = <T extends ValidComponent = "div">( props: PolymorphicProps<T, popoverContentProps<T>>, ) => { const [local, rest] = splitProps(props as popoverContentProps, [ "class", "children", ]); return ( <PopoverPrimitive.Portal> <PopoverPrimitive.Content class={cn( "z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[expanded]:animate-in data-[closed]:animate-out data-[closed]:fade-out-0 data-[expanded]:fade-in-0 data-[closed]:zoom-out-95 data-[expanded]:zoom-in-95", local.class, )} {...rest} > {local.children} <PopoverPrimitive.CloseButton class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-[opacity,box-shadow] hover:opacity-100 focus:outline-none focus:ring-[1.5px] focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-4 w-4" > <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 6L6 18M6 6l12 12" /> <title>Close</title> </svg> </PopoverPrimitive.CloseButton> </PopoverPrimitive.Content> </PopoverPrimitive.Portal> ); };
import { cn } from "@/libs/cn"; import type { PolymorphicProps } from "@kobalte/core/polymorphic"; import type { PopoverContentProps, PopoverRootProps, } from "@kobalte/core/popover"; import { Popover as PopoverPrimitive } from "@kobalte/core/popover"; import type { ParentProps, ValidComponent } from "solid-js"; import { mergeProps, splitProps } from "solid-js"; export const PopoverTrigger = PopoverPrimitive.Trigger; export const PopoverTitle = PopoverPrimitive.Title; export const PopoverDescription = PopoverPrimitive.Description; export const Popover = (props: PopoverRootProps) => { const merge = mergeProps<PopoverRootProps[]>( { gutter: 4, flip: false, }, props, ); return <PopoverPrimitive {...merge} />; }; type popoverContentProps<T extends ValidComponent = "div"> = ParentProps< PopoverContentProps<T> & { class?: string; } >; export const PopoverContent = <T extends ValidComponent = "div">( props: PolymorphicProps<T, popoverContentProps<T>>, ) => { const [local, rest] = splitProps(props as popoverContentProps, [ "class", "children", ]); return ( <PopoverPrimitive.Portal> <PopoverPrimitive.Content class={cn( "z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[expanded]:(animate-in fade-in-0 zoom-in-95) data-[closed]:(animate-out fade-out-0 zoom-out-95)", local.class, )} {...rest} > {local.children} <PopoverPrimitive.CloseButton class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:(outline-none ring-1.5 ring-ring ring-offset-2) disabled:pointer-events-none bg-inherit transition-property-[opacity,box-shadow]"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-4 w-4" > <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 6L6 18M6 6l12 12" /> <title>Close</title> </svg> </PopoverPrimitive.CloseButton> </PopoverPrimitive.Content> </PopoverPrimitive.Portal> ); };
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
<Popover> <PopoverTrigger>Open</PopoverTrigger> <PopoverContent>Place content for the popover here.</PopoverContent> </Popover>