All Taste components
Forms
Input with icon & button
Inputs with a leading icon or a trailing action: search, copy a link, show a password.
search + shortcut · copy link · password reveal
/
"use client";
import { useState } from "react";
import { Check, Copy, Eye, EyeOff, Lock, Search } from "lucide-react";
import { cn } from "@/lib/utils";
const shell =
"flex h-9 w-full min-w-0 items-center gap-2 rounded border border-border-strong bg-bg px-2.5 transition focus-within:border-primary focus-within:ring-[3px] focus-within:ring-primary/20";
const bare = "h-full min-w-0 flex-1 bg-transparent text-sm text-fg outline-none placeholder:text-fg-subtle";
export function SearchInput({ className, ...props }: React.InputHTMLAttributes<HTMLInputElement>) {
return (
<div className={cn(shell, className)}>
<Search className="size-4 shrink-0 text-fg-subtle" aria-hidden />
<input type="search" className={bare} {...props} />
<kbd className="rounded-sm border border-b-2 border-border-strong bg-surface px-1.5 font-mono text-[11px] text-fg-muted">/</kbd>
</div>
);
}
export function CopyLinkInput({ url, label = "Link" }: { url: string; label?: string }) {
const [copied, setCopied] = useState(false);
async function copy() {
await navigator.clipboard.writeText(url);
setCopied(true);
setTimeout(() => setCopied(false), 1600);
}
return (
<div className="flex h-9 w-full min-w-0 overflow-hidden rounded border border-border-strong bg-bg transition focus-within:border-primary focus-within:ring-[3px] focus-within:ring-primary/20">
<input readOnly value={url} aria-label={label} onFocus={(e) => e.target.select()} className={cn(bare, "px-3")} />
<button
type="button"
onClick={copy}
className="inline-flex shrink-0 items-center gap-1.5 border-l border-border bg-surface px-3 text-sm font-medium text-fg transition hover:bg-surface-2"
>
{copied ? <Check className="size-4 text-success" aria-hidden /> : <Copy className="size-4" aria-hidden />}
{copied ? "Copied" : "Copy"}
</button>
<span className="sr-only" aria-live="polite">{copied ? "Link copied" : ""}</span>
</div>
);
}
export function PasswordInput(props: Omit<React.InputHTMLAttributes<HTMLInputElement>, "type">) {
const [shown, setShown] = useState(false);
return (
<div className={shell}>
<Lock className="size-4 shrink-0 text-fg-subtle" aria-hidden />
<input type={shown ? "text" : "password"} className={bare} {...props} />
<button
type="button"
onClick={() => setShown((s) => !s)}
aria-label={shown ? "Hide password" : "Show password"}
aria-pressed={shown}
className="-mr-1 grid size-7 shrink-0 place-items-center rounded-sm text-fg-muted transition hover:bg-surface-2 hover:text-fg"
>
{shown ? <EyeOff className="size-4" aria-hidden /> : <Eye className="size-4" aria-hidden />}
</button>
</div>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.