Input
Text input whose focus ring grows from a hairline to two px, with a destructive ring for aria-invalid.
"use client";
import { useId } from "react";
import { Input } from "@/components/motion/input";
export function InputPreview() {
const emailId = useId();
const usernameId = useId();
const errorId = useId();
return (
<div className="flex w-full max-w-xs flex-col gap-4">
<label htmlFor={emailId} className="flex flex-col gap-2 text-sm">
<span className="font-medium text-foreground">Email</span>
<Input id={emailId} type="email" placeholder="name@company.com" autoComplete="email" />
</label>
<label htmlFor={usernameId} className="flex flex-col gap-2 text-sm">
<span className="font-medium text-foreground">Username</span>
<Input
id={usernameId}
defaultValue="taken"
aria-invalid="true"
aria-describedby={errorId}
/>
<span id={errorId} className="text-xs text-destructive">
That username is already taken.
</span>
</label>
</div>
);
}
"use client";
// easeui.dev/components/motion/input
import { forwardRef, type InputHTMLAttributes } from "react";
import { cn } from "@/lib/utils";
export type InputProps = InputHTMLAttributes<HTMLInputElement>;
/**
* Text input whose focus ring grows from a hairline to two px. Pass
* aria-invalid to switch the ring to the destructive color.
*/
export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
{ className, ...props },
ref,
) {
return (
<input
ref={ref}
className={cn(
"h-10 w-full rounded-xl bg-card px-3 text-base text-foreground shadow-[0_0_0_1px_var(--border-strong)] outline-none transition-shadow duration-150 ease-out sm:text-sm",
"placeholder:text-muted-foreground",
"focus:shadow-[0_0_0_2px_var(--accent)]",
"aria-invalid:shadow-[0_0_0_2px_var(--destructive)]",
"disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
/>
);
});
Installation
$ bunx --bun shadcn add @easeui/input
- 1
Set up the theme tokens
Do this once per project. Follow the theme setup or skip it if you already ran shadcn init.
- 2
Install the dependencies
terminal npm install clsx tailwind-merge - 3
Add the source files
components/motion/input.tsx "use client"; // easeui.dev/components/motion/input import { forwardRef, type InputHTMLAttributes } from "react"; import { cn } from "@/lib/utils"; export type InputProps = InputHTMLAttributes<HTMLInputElement>; /** * Text input whose focus ring grows from a hairline to two px. Pass * aria-invalid to switch the ring to the destructive color. */ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input( { className, ...props }, ref, ) { return ( <input ref={ref} className={cn( "h-10 w-full rounded-xl bg-card px-3 text-base text-foreground shadow-[0_0_0_1px_var(--border-strong)] outline-none transition-shadow duration-150 ease-out sm:text-sm", "placeholder:text-muted-foreground", "focus:shadow-[0_0_0_2px_var(--accent)]", "aria-invalid:shadow-[0_0_0_2px_var(--destructive)]", "disabled:cursor-not-allowed disabled:opacity-50", className, )} {...props} /> ); });lib/utils.ts import { clsx, type ClassValue } from "clsx" import { twMerge } from "tailwind-merge" export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) }
API reference
Updated