Input
A text input field for capturing user data.
ui/input.tsx
"use client";
import { CircleXFilledIcon } from "blode-icons-react";
import * as React from "react";
import { cn } from "@/lib/utils";
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
clearable?: boolean;
clearClassName?: string;
hasError?: boolean;
leftAddon?: React.ReactNode | null;
leftControl?: React.ReactNode | null;
onClear?: () => void;
rightAddon?: React.ReactNode | null;
rightControl?: React.ReactNode | null;
}
const Input = ({
className,
clearClassName,
hasError,
clearable,
onClear,
leftAddon,
rightAddon,
leftControl,
rightControl,
ref,
...props
}: InputProps & { ref?: React.Ref<HTMLInputElement> }) => (
<label
className={cn("relative block w-full", {
"input-group": !!leftAddon || !!rightAddon,
})}
>
{leftAddon && <span className="shrink-0 cursor-pointer">{leftAddon}</span>}
{leftControl && (
<div className="absolute top-0 left-0 flex h-full flex-row place-items-center items-center justify-center">
{leftControl}
</div>
)}
<div className="w-full">
<input
aria-invalid={hasError || undefined}
className={cn(
"input flex h-[var(--field-height)] w-full rounded-[var(--field-radius)] border border-input bg-card px-[var(--field-padding-x)] py-[var(--field-padding-y)] font-normal font-sans text-base text-foreground leading-snug shadow-input transition-colors placeholder:text-placeholder-foreground hover:border-input-hover focus:border-ring focus:outline-hidden focus:ring-2 focus:ring-ring/15 focus:ring-offset-1 focus:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50",
{
"border-destructive-foreground": hasError,
"hover:border-input! focus:border-input!": props.readOnly,
"pr-12": clearable && !!props.value && rightControl,
"pr-9": clearable && !!props.value,
},
className,
)}
ref={ref}
{...props}
/>
{clearable && !!props.value && (
<div className="absolute top-0 right-0 flex flex-row gap-1 pr-3">
<button
aria-label="clear input"
className={cn(
"flex h-[var(--field-height)] cursor-pointer items-center justify-center p-0! text-muted-foreground",
clearClassName,
)}
onClick={() => onClear?.()}
tabIndex={-1}
type="button"
>
<CircleXFilledIcon className="size-5 text-muted-foreground/50" />
</button>
</div>
)}
</div>
{rightControl && (
<div
className={cn(
"absolute top-0 right-0 flex h-full flex-row place-items-center items-center justify-center",
{
"right-9": clearable && !!props.value,
},
)}
>
{rightControl}
</div>
)}
{rightAddon && <span className="shrink-0 cursor-pointer">{rightAddon}</span>}
</label>
);
export { Input };
No selection tags yet — empty means no evidence, not lack of support.
DependenciesBundle weight · light
blode-icons-react