Vela UI Docsvenizia.ai

Input

A text input component for forms and user data entry with built-in styling and accessibility features.

npx shadcn@latest add @velaui/input
npx shadcn@latest add @velaui/input

Examples

  • Variants
  • With label
  • Disabled
  • Rounded
  • Start helper text
  • End helper text
  • Hint text
  • Invalid
  • Colored ring
  • Characters left

View code

Input · Variants

Installation

pnpm dlx velaui add @velaui/input
pnpm dlx velaui add @velaui/input

Code

input-variants.tsx
import { Input } from "@/components/ui/input";

export default function Example() {
  return (
    <div className="flex flex-col gap-y-3">
      <Input id="outlined" variant={"outlined"} placeholder="outlined" />
      <Input id="fill" variant={"fill"} placeholder="fill" />
      <Input id="underline" variant={"underline"} placeholder="underline" />
    </div>
  );
}

View code

Input · With label

Installation

pnpm dlx velaui add @velaui/input
pnpm dlx velaui add @velaui/input

Code

input-with-label.tsx
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";

export default function Example() {
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor="email">Input with label</Label>
      <Input id="email" type="email" placeholder="Email address" />
    </div>
  );
}

View code

Input · Disabled

Installation

pnpm dlx velaui add @velaui/input
pnpm dlx velaui add @velaui/input

Code

input-disabled.tsx
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";

export default function Example() {
  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor="username">Disabled input</Label>
      <Input id="username" disabled placeholder="Username" />
    </div>
  );
}

View code

Input · Rounded

Installation

pnpm dlx velaui add @velaui/input
pnpm dlx velaui add @velaui/input

Code

input-rounded.tsx
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { useId } from "react";

export default function Example() {
  const id = useId();

  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Rounded Input</Label>
      <Input
        id={id}
        type="email"
        placeholder="Email address"
        className="rounded-full"
      />
    </div>
  );
}

View code

Input · Start helper text

Installation

pnpm dlx velaui add @velaui/input
pnpm dlx velaui add @velaui/input

Code

input-start-helper-text.tsx
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { useId } from "react";

export default function Example() {
  const id = useId();

  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Input with start helper text</Label>
      <Input id={id} placeholder="Enter room id" />
      <p className="text-muted-foreground text-xs">
        Enter room id to play co-op mode
      </p>
    </div>
  );
}

View code

Input · End helper text

Installation

pnpm dlx velaui add @velaui/input
pnpm dlx velaui add @velaui/input

Code

input-end-helper-text.tsx
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { useId } from "react";

export default function Example() {
  const id = useId();

  return (
    <div className="w-fit max-w-xs space-y-2">
      <Label htmlFor={id}>Input with end helper text</Label>
      <Input id={id} placeholder="Enter room id" />
      <p className="text-muted-foreground text-xs text-end">
        Enter room id to play co-op mode
      </p>
    </div>
  );
}

View code

Input · Hint text

Installation

pnpm dlx velaui add @velaui/input
pnpm dlx velaui add @velaui/input

Code

input-hint-text.tsx
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { useId } from "react";

export default function Example() {
  const id = useId();

  return (
    <div className="w-full max-w-xs space-y-2">
      <div className="flex items-center justify-between">
        <Label htmlFor={id}>Input with hint text</Label>
        <span className="text-muted-foreground text-xs">optional</span>
      </div>
      <Input id={id} placeholder="Enter email address..." />
    </div>
  );
}

View code

Input · Invalid

Installation

pnpm dlx velaui add @velaui/input
pnpm dlx velaui add @velaui/input

Code

input-invalid.tsx
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { useId } from "react";

export default function Example() {
  const id = useId();

  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Invalid input</Label>
      <Input
        id={id}
        type="email"
        placeholder="Enter email"
        className="peer"
        defaultValue={"helloworld@gmail.com"}
        aria-invalid
      />
      <p className="text-muted-foreground peer-aria-invalid:text-destructive text-xs">
        Invalid email
      </p>
    </div>
  );
}

View code

Input · Colored ring

Installation

pnpm dlx velaui add @velaui/input
pnpm dlx velaui add @velaui/input

Code

input-colored-ring.tsx
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { useId } from "react";

export default function Example() {
  const id = useId();

  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Input with colored ring</Label>
      <Input
        id={id}
        placeholder="Username"
        className="focus-visible:border-purple-500 focus-visible:ring-purple-500/20 dark:focus-visible:ring-purple-500/40"
      />
    </div>
  );
}

View code

Input · Characters left

Installation

pnpm dlx velaui add @velaui/input
pnpm dlx velaui add @velaui/input

Code

input-characters-left.tsx
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { ChangeEvent, useId, useState } from "react";

const MAX_LENGTH = 20;
const initialValue = ''

export default function Example() {
  const id = useId();
  const [value, setValue] = useState(initialValue);

  const handleOnChange = (e: ChangeEvent<HTMLInputElement>) => {
    if(e.target.value.length <= MAX_LENGTH) {
      setValue(e.target.value);
    }
  }

  return (
    <div className="w-full max-w-xs space-y-2">
      <Label htmlFor={id}>Input with characters left</Label>
      <Input id={id} placeholder="Username" value={value} onChange={handleOnChange}/>
      <p className="text-muted-foreground text-xs">{MAX_LENGTH - value.length} characters left</p>
    </div>
  )
}

Sizes

Usage

import { Input } from "@/components/ui/input";

export default function Example() {
  return (
    <div className="flex flex-col gap-y-3">
      <Input id="outlined" variant={"outlined"} placeholder="outlined" />
      <Input id="fill" variant={"fill"} placeholder="fill" />
      <Input id="underline" variant={"underline"} placeholder="underline" />
    </div>
  );
}

Props

PropTypeDefault
size"sm" | "md" | "lg""sm"
variant"fill" | "underline" | "outlined""outlined"

Takes these and every prop of InputProps.

PropTypeDefault
size"sm" | "md" | "lg""sm"
variant"underline" | "fill" | "outlined""outlined"

Takes these and every prop of InputProps.

Dependencies

npm
class-variance-authority@0.7.1
Installs with it
nothing else

Source

components/ui/input.tsx
/* eslint-disable react-refresh/only-export-components */
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";

import { cn } from "@/lib/utils";

const inputVariants = cva(
  "w-full min-w-0 text-sm leading-[1.4] text-text-strong transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-text-strong placeholder:text-text-note disabled:pointer-events-none disabled:cursor-not-allowed disabled:text-text-disabled",
  {
    variants: {
      variant: {
        outlined:
          "rounded-md border border-border-default bg-bg-main hover:border-border-hover hover:bg-input-hover focus-visible:border-ring-neutral-outline focus-visible:bg-input-default focus-visible:ring-3 focus-visible:ring-ring-neutral-shadow disabled:border-border-disabled disabled:bg-input-disabled aria-invalid:border-negative-middle aria-invalid:focus-visible:border-negative-middle aria-invalid:focus-visible:ring-negative-middle/25",
        // Fill draws no border at rest, but hover/focus/invalid all draw a 1px
        // one — reserve it as transparent so entering a state never reflows.
        fill: "rounded-md border border-transparent bg-input-default hover:border-border-hover hover:bg-input-hover focus-visible:border-ring-neutral-outline focus-visible:ring-3 focus-visible:ring-ring-neutral-shadow disabled:border-transparent disabled:bg-input-disabled aria-invalid:border-negative-middle aria-invalid:focus-visible:border-negative-middle aria-invalid:focus-visible:ring-negative-middle/25",
        // Underline carries no surface, no radius and no focus ring — the whole
        // state vocabulary lives on the bottom border.
        underline:
          "rounded-none border-0 border-b border-b-border-default bg-transparent hover:border-b-border-active focus-visible:border-b-border-active disabled:border-b-border-default disabled:bg-transparent aria-invalid:border-b-negative-middle aria-invalid:focus-visible:border-b-negative-middle",
      },
      size: {
        sm: "h-8 px-2.5 py-1.5",
        md: "h-10 px-3 py-2.5",
        lg: "h-12 px-4 py-3.5",
      },
    },
    compoundVariants: [
      {
        variant: "underline",
        size: ["sm", "md", "lg"],
        className: "px-0",
      },
    ],
    defaultVariants: {
      variant: "outlined",
      size: "sm",
    },
  },
);

export type InputProps = Omit<React.ComponentProps<"input">, "size"> &
  VariantProps<typeof inputVariants>;

function Input({
  className,
  type,
  variant = "outlined",
  size = "sm",
  ...props
}: InputProps) {
  return (
    <input
      type={type}
      data-slot="input"
      data-variant={variant}
      data-size={size}
      className={cn(inputVariants({ variant, size }), className)}
      {...props}
    />
  );
}

export { Input, inputVariants };