Input Copy
fluid-functionalism/input-copyFreeComponent
Read-only input with a copy-to-clipboard button and animated check feedback. Supports optional label and shape context.
Install it
npx shadcn@latest add https://fluidfunctionalism.com/r/input-copy.jsonSource
1"use client";23import { forwardRef, useState, useCallback, useRef, useEffect, useId, type HTMLAttributes } from "react";4import { motion, AnimatePresence } from "framer-motion";5import { cn } from "@/lib/utils";6import { useIcon } from "@/lib/icon-context";7import { fontWeights } from "@/lib/font-weight";8import { useShape } from "@/lib/shape-context";9import { spring } from "@/lib/springs";10import { Tooltip } from "@/registry/radix/tooltip";1112type InputCopyVariant = "icon" | "button";13type InputCopyAlign = "right" | "left";1415interface InputCopyProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {16 /** The value to display and copy to clipboard. */17 value: string;18 /** Optional label displayed above the input. */19 label?: string;20 /** Callback fired after the value is copied. */21 onCopy?: () => void;22 /** Whether the component is disabled. */23 disabled?: boolean;24 /** Display variant: icon-only with tooltip, or button with label. */25 variant?: InputCopyVariant;26 /** Position of the copy action relative to the value. */27 align?: InputCopyAlign;28}2930const InputCopy = forwardRef<HTMLDivElement, InputCopyProps>(31 ({ value, label, onCopy, disabled, variant = "icon", align = "right", className, ...props }, ref) => {32 const CopyIcon = useIcon("copy");33 // "copied" and "error" both occupy the same animation slot on the button34 const [status, setStatus] = useState<"idle" | "copied" | "error">("idle");35 const [copyCount, setCopyCount] = useState(0);36 // "idle" = normal tooltip behavior, "copied" = force open, "suppressed" = force closed37 const [tooltipState, setTooltipState] = useState<"idle" | "copied" | "suppressed">("idle");38 const timeoutRef = useRef<ReturnType<typeof setTimeout>>(null);39 const tooltipVisibleRef = useRef(false);40 const tooltipWasVisibleRef = useRef(false);41 const shape = useShape();4243 // Associate the visible label with the button: the button's accessible44 // name reads "Copy <label>" (its own state label + the field label).45 const generatedId = useId();46 const labelId = label ? `${generatedId}-label` : undefined;47 const buttonId = `${generatedId}-button`;4849 const handlePointerDown = useCallback(() => {50 // Capture tooltip visibility before Radix closes it on pointer down51 tooltipWasVisibleRef.current = tooltipVisibleRef.current;52 }, []);5354 // execCommand fallback for when the async Clipboard API is unavailable or55// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from fluid-functionalism
All 53 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | fluid-functionalism | Components | Free | 3 deps | |
| Accordion (Base UI)accordion-base | fluid-functionalism | Components | Free | 3 deps | |
| Ask User Questionsask-user-questions | fluid-functionalism | Components | Free | 2 deps | |
| Badgebadge | fluid-functionalism | Components | Free | 1 dep | |
| Buttonbutton | fluid-functionalism | Components | Free | 4 deps | |
| Button (Base UI)button-base | fluid-functionalism | Components | Free | 4 deps | |
| Cardcard | fluid-functionalism | Components | Free | 1 dep | |
| Chat Messagechat-message | fluid-functionalism | Components | Free | 1 dep |
