Input
Displays a form input field or a component that looks like an input field.
Basic Usage
import { Input } from "@repo/ui/components/input";
interface Example1Props {}
export const Example1: React.FC<Example1Props> = ({}) => {
return (
<div className="sm:w-80">
<Input type="email" placeholder="Email" />
</div>
);
};
File Input
import { Input } from "@repo/ui/components/input";
import { Label } from "@repo/ui/components/label";
interface Example2Props {}
export const Example2: React.FC<Example2Props> = ({}) => {
return (
<div className="flex flex-col gap-3 sm:w-80">
<Label htmlFor="picture">Picture</Label>
<Input id="picture" type="file" />
</div>
);
};
Disabled Input Field
import { Input } from "@repo/ui/components/input";
interface Example3Props {}
export const Example3: React.FC<Example3Props> = ({}) => {
return (
<div className="sm:w-80">
<Input type="email" placeholder="Email disabled" disabled={true} />
</div>
);
};
Input with Label
import { Input } from "@repo/ui/components/input";
import { Label } from "@repo/ui/components/label";
interface Example4Props {}
export const Example4: React.FC<Example4Props> = ({}) => {
return (
<div className="flex flex-col gap-3 sm:w-80">
<Label htmlFor="email">Email</Label>
<Input type="email" id="email" placeholder="Email" />
</div>
);
};
Input with Button
import { Button } from "@repo/ui/components/button";
import { Input } from "@repo/ui/components/input";
interface Example5Props {}
export const Example5: React.FC<Example5Props> = ({}) => {
return (
<div className="flex gap-3 sm:w-96">
<Input type="email" placeholder="Email" />
<Button type="submit" className="rounded-lg">
Subscribe
</Button>
</div>
);
};
Component Code
"use client";
import { cn } from "@repo/ui/lib/utils";
import { ComponentProps, forwardRef, useRef } from "react";
import { AriaTextFieldProps, useFocusRing, useTextField } from "react-aria";
import { mergeProps } from "@react-aria/utils";
type InputComponentProps = ComponentProps<"input">;
interface InputProps
extends InputComponentProps,
Omit<AriaTextFieldProps, keyof InputComponentProps> {
className?: string;
}
export const Input = forwardRef<HTMLInputElement, InputProps>(
({ className = "", type = "text", ...restProps }, ref) => {
const localRef = useRef<HTMLInputElement>(null);
const mergedRef = (node: HTMLInputElement | null) => {
if (!node) {
return;
}
localRef.current = node;
if (typeof ref == "function") {
ref(node);
} else if (ref) {
ref.current = node;
}
};
const { inputProps } = useTextField(
restProps as AriaTextFieldProps,
localRef,
);
const { focusProps } = useFocusRing();
return (
<input
{...mergeProps(inputProps, focusProps, restProps)}
type={type}
ref={mergedRef}
className={cn(
"file:text-foreground placeholder:text-muted-foreground",
"selection:bg-primary selection:text-primary-foreground",
"dark:bg-input/30 border-input shadow-xs h-9 w-full min-w-0",
"rounded-md border bg-transparent px-3 py-1 text-base outline-none",
"transition-[color,box-shadow] file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium",
"disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
className,
)}
/>
);
},
);
Input.displayName = "Input";