Vela UI Docsvenizia.ai

Textarea

Displays a form textarea or a component that looks like a textarea.

npx shadcn@latest add @velaui/textarea
npx shadcn@latest add @velaui/textarea

Examples

  • Default
  • With label
  • With label helper text
  • Disabled
  • Invalid
  • With button

View code

Textarea · Default

Installation

pnpm dlx velaui add @velaui/textarea
pnpm dlx velaui add @velaui/textarea

Code

textarea-default.tsx
import { Textarea } from "@/components/ui/textarea";

export default function Example() {
  return <Textarea placeholder="Share your thoughts…" />;
}

View code

Textarea · With label

Installation

pnpm dlx velaui add @velaui/textarea
pnpm dlx velaui add @velaui/textarea

Code

textarea-with-label.tsx
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
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}>Textarea with label</Label>
      <Textarea id={id} placeholder="Enter description..." />
    </div>
  );
}

View code

Textarea · With label helper text

Installation

pnpm dlx velaui add @velaui/textarea
pnpm dlx velaui add @velaui/textarea

Code

textarea-with-label-helper-text.tsx
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
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}>Textarea with label + helper text</Label>
      <Textarea id={id} placeholder="Share your thoughts..." />
      <p className="text-muted-foreground text-xs">helper text</p>
    </div>
  );
}

View code

Textarea · Disabled

Installation

pnpm dlx velaui add @velaui/textarea
pnpm dlx velaui add @velaui/textarea

Code

textarea-disabled.tsx
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
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}>Disabled input</Label>
      <Textarea id={id} placeholder="Note...." disabled />
    </div>
  );
}

View code

Textarea · Invalid

Installation

pnpm dlx velaui add @velaui/textarea
pnpm dlx velaui add @velaui/textarea

Code

textarea-invalid.tsx
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
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 textarea</Label>
      <Textarea id={id} placeholder="Type your message here." aria-invalid />
      <p className="text-destructive text-xs">Please enter a valid message.</p>
    </div>
  );
}

View code

Textarea · With button

Installation

pnpm dlx velaui add @velaui/textarea
pnpm dlx velaui add @velaui/textarea

Code

textarea-with-button.tsx
import {
  InputGroup,
  InputGroupAddon,
  InputGroupButton,
  InputGroupTextarea,
} from "@/components/ui/input-group";
import { Label } from "@/components/ui/label";
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}>Textarea with button</Label>
      <InputGroup>
        <InputGroupTextarea id={id} placeholder="Share your thoughts..." />
        <InputGroupAddon align={"block-end"}>
          <InputGroupButton variant={"primary"} className="ml-auto">
            Send
          </InputGroupButton>
        </InputGroupAddon>
      </InputGroup>
    </div>
  );
}

Usage

import { Textarea } from "@/components/ui/textarea";

export default function Example() {
  return <Textarea placeholder="Share your thoughts…" />;
}

Props

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

Takes these and every prop of TextareaProps.

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

Takes these and every prop of TextareaProps.

Dependencies

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

Source

components/ui/textarea.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 textareaVariants = cva(
  "field-sizing-content w-full min-w-0 text-sm leading-[1.4] text-text-strong transition-colors outline-none 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: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: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 focus/invalid both draw a 1px one —
        // reserve it as transparent so entering a state never reflows.
        fill: "rounded-md border border-transparent bg-input-default 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: "min-h-15 px-2.5 py-1.5",
        md: "min-h-22 px-3 py-2.5",
        lg: "min-h-25 px-4 py-3.5",
      },
    },
    compoundVariants: [
      {
        variant: "underline",
        size: ["sm", "md", "lg"],
        className: "px-0",
      },
    ],
    defaultVariants: {
      variant: "outlined",
      size: "md",
    },
  },
);

export type TextareaProps = React.ComponentProps<"textarea"> &
  VariantProps<typeof textareaVariants>;

function Textarea({
  className,
  variant = "outlined",
  size = "md",
  ...props
}: TextareaProps) {
  return (
    <textarea
      data-slot="textarea"
      data-variant={variant}
      data-size={size}
      className={cn(textareaVariants({ variant, size }), className)}
      {...props}
    />
  );
}

export { Textarea, textareaVariants };