Displays a form input field or a component that looks like an input field.
Installation
npx shadcn@latest add @caprice/inputpnpm dlx shadcn@latest add @caprice/inputyarn dlx shadcn@latest add @caprice/inputbunx shadcn@latest add @caprice/inputnpm install @caprice-ui/reactpnpm add @caprice-ui/reactyarn add @caprice-ui/reactbun add @caprice-ui/reactInstall the following dependencies:
npm install @base-ui/react lucide-reactpnpm add @base-ui/react lucide-reactyarn add @base-ui/react lucide-reactbun add @base-ui/react lucide-reactAdd a cn helper
import { defineConfig, getSchema, type VariantProps } from 'cva';
import { twMerge } from 'tailwind-merge';
export const { cva, cx: cn } = defineConfig({
hooks: {
onComplete: (className: string) => twMerge(className),
},
});
export type { VariantProps };
export { getSchema };
Copy and paste the following code into your project.
'use client';
import { mergeProps } from '@base-ui/react';
import { Input as InputPrimitive } from '@base-ui/react/input';
import type * as React from 'react';
import { type PressEvents, useFocusRing, usePress } from 'react-aria';
import { cva, type VariantProps } from '@/lib/utils';
export const inputVariants = cva({
base: [
'field-sizing-content w-full min-w-0 rounded-md border border-input py-1 shadow-xs outline-none selection:bg-primary selection:text-primary-foreground placeholder:text-muted-foreground dark:bg-input/30',
// Transition
'transition-[color,background-color,border-color,box-shadow]',
// File
'file:inline-flex file:border-0 file:bg-transparent file:font-medium file:text-foreground',
// Focus state, using focus instead of focus-visible to avoid confusion with data-focus-visible
'focus:border-ring focus:ring-[3px] focus:ring-ring/50 focus:placeholder:text-current',
// Real "focus-visible", only visible when interacting with a keyboard.
// ref: https://react-spectrum.adobe.com/react-aria/useFocusRing.html
'data-focus-visible:outline-2 data-focus-visible:outline-primary data-focus-visible:outline-solid data-focus-visible:outline-offset-2 data-focus-visible:ring-transparent dark:data-focus-visible:outline-primary/64',
// Disabled state
'disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
// Invalid state
'aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-invalid:data-focus-visible:outline-destructive/80 dark:aria-invalid:data-focus-visible:outline-destructive/48',
],
variants: {
variant: {
outline: [
'bg-transparent',
// Hover state
'not-disabled:hover:not-focus-within:bg-input/32 not-disabled:hover:not-focus-within:placeholder:text-current dark:not-disabled:hover:not-focus-within:bg-input/72',
// Pressed state
'data-pressed:bg-input/48 dark:data-pressed:bg-input/84',
],
},
size: {
md: 'h-9 px-3 text-base file:h-7 md:text-sm',
lg: 'h-12 px-4 text-base file:h-10',
xl: 'h-14 px-4 text-xl file:h-12',
},
},
defaultVariants: {
size: 'md',
variant: 'outline',
},
});
/**
* A native input element that automatically works with [Field](https://base-ui.com/react/components/field).
* Renders an `<input>` element.
*
* Documentation: [Caprice UI Input](https://caprice-ui.com/docs/components/input)
*
* API Reference: [Base UI Input](https://base-ui.com/react/components/input)
*/
export namespace Input {
export type State = InputPrimitive.State;
export type Variants = {
/**
* Size
* @default 'md'
*/
size?: VariantProps<typeof inputVariants>['size'] | number;
/**
* Variant
* @default 'outline'
*/
variant?: VariantProps<typeof inputVariants>['variant'];
};
export type Props = Omit<React.ComponentProps<typeof InputPrimitive>, 'size'> &
PressEvents &
Input.Variants;
export type ChangeEventDetails = InputPrimitive.ChangeEventDetails;
export type ChangeEventReason = InputPrimitive.ChangeEventReason;
}
export function Input({
className,
size,
variant,
// PressEvents
onPress,
onPressStart,
onPressChange,
onPressEnd,
onPressUp,
onClick,
...props
}: Input.Props) {
const { isFocusVisible, focusProps } = useFocusRing({ isTextInput: true });
const { pressProps, isPressed } = usePress({
onPress,
onPressStart,
onPressChange,
onPressEnd,
onPressUp,
onClick,
isDisabled: props.disabled,
});
const defaultProps: React.ComponentProps<'input'> & { 'data-slot'?: string } = {
'data-slot': 'input',
className: inputVariants({
variant,
size: typeof size === 'string' ? size : undefined,
className,
}),
};
const inputProps = mergeProps<typeof InputPrimitive>(defaultProps, focusProps, pressProps, props);
return (
<InputPrimitive
data-focus-visible={isFocusVisible ? '' : undefined}
data-pressed={isPressed ? '' : undefined}
size={typeof size === 'number' ? size : undefined}
{...inputProps}
/>
);
}
Update the import paths to match your project setup.
Usage
import { Input } from "@/components/caprice-ui/input"import { Input } from "@caprice-ui/react/input"<Input />Examples
Sizes
File
Disabled
Invalid
With Label
With Button
Variants
Prop
Type
Default
Last updated on