Preview Rail
beui/preview-railFreeComponent
Codex app-inspired navigation rail with compact ticks that form a hover pyramid and reveal a floating destination preview.
Install it
npx shadcn@latest add https://beui.dev/r/preview-rail.jsonSource
1"use client";2// beui.dev/components/motion/preview-rail34import { AnimatePresence, motion, useReducedMotion } from "motion/react";5import { useId, useState, type ReactNode } from "react";6import { EASE_OUT, SPRING_LAYOUT } from "@/lib/ease";7import { useHoverCapable } from "@/lib/hooks/use-hover-capable";8import { cn } from "@/lib/utils";910export interface PreviewRailItem {11 id: string;12 label: string;13 ariaLabel?: string;14 description?: ReactNode;15 href?: string;16 target?: "_blank" | "_self" | "_parent" | "_top";17 rel?: string;18}1920export interface PreviewRailProps {21 items: PreviewRailItem[];22 label?: string;23 orientation?: "vertical" | "horizontal";24 activeId?: string;25 defaultActiveId?: string;26 onActiveChange?: (id: string) => void;27 onItemSelect?: (item: PreviewRailItem) => void;28 renderPreview?: (item: PreviewRailItem) => ReactNode;29 showPreview?: boolean;30 previewSide?: "before" | "after";31 highlightActive?: boolean;32 itemSize?: number;33 children?: ReactNode;34 className?: string;35 railClassName?: string;36 previewContainerClassName?: string;37 previewClassName?: string;38}3940function DefaultPreview({ item }: { item: PreviewRailItem }) {41 return (42 <div43 data-slot="preview-rail-card"44 className="rounded-2xl border border-border bg-card p-4 shadow-sm"45 >46 <p47 data-slot="preview-rail-title"48 className="font-medium text-card-foreground"49 >50 {item.label}51 </p>52 {item.description ? (53 <div54 data-slot="preview-rail-description"55 className="mt-1 text-sm leading-6 text-muted-foreground"56 >57 {item.description}58 </div>59 ) : null}60 </div>61 );62}6364export function PreviewRail({65 items,66 label = "Section navigation",67 orientation = "vertical",68 activeId,69 defaultActiveId,70 onActiveChange,71 onItemSelect,72 renderPreview,73 showPreview = true,74 previewSide = "after",75 highlightActive = false,76 itemSize = 24,77 children,78 className,79 railClassName,80 previewContainerClassName,81 previewClassName,82}: PreviewRailProps) {83 const uid = useId();84 const reduce = useReducedMotion();85 const canHover = useHoverCapable();86 const [internalActiveId, setInternalActiveId] = useState(87 defaultActiveId ?? items[0]?.id ?? "",88 );89 const [hoveredId, setHoveredId] = useState<string | null>(null);90 const [focusedId, setFocusedId] = useState<string | null>(null);9192 const requestedActiveId = activeId ?? internalActiveId;93// … truncated
What it pulls in
npm packages
Files it writes
More from beui
All 104 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Action Swap Bluraction-swap-blur | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Cascadeaction-swap-cascade | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Rollaction-swap-roll | beui | Components | Free | 3 deps · 4 files | |
| Agent Activityagent-activity | beui | Components | Free | 4 deps · 9 files | |
| Agent Loading States Agent Progressagent-progress | beui | Components | Free | 3 deps · 3 files | |
| AI Sidebarai-sidebar | beui | Components | Free | 4 deps · 5 files | |
| Animated Badgeanimated-badge | beui | Components | Free | 4 deps · 3 files | |
| Number Animation Animated Numberanimated-number | beui | Components | Free | 3 deps · 3 files |
