Textarea
Displays a form textarea or a component that looks like a textarea.
npx shadcn@latest add @velaui/textareapnpm dlx velaui add @velaui/textareayarn dlx shadcn@latest add @velaui/textareabunx --bun shadcn@latest add @velaui/textareaveni add textareaInstalls the copy of vela-ui that veni-builder serves to Venizia apps; veni-builder serves the Radix UI copy only, so this tab exists for that base alone.
npx shadcn@latest add @velaui/textareapnpm dlx velaui add @velaui/textareayarn dlx shadcn@latest add @velaui/textareabunx --bun shadcn@latest add @velaui/textareaExamples
- Default
- With label
- With label helper text
- Disabled
- Invalid
- With button
Usage
Props
| Prop | Type | Default |
|---|---|---|
size | "sm" | "md" | "lg" | "md" |
variant | "fill" | "underline" | "outlined" | "outlined" |
Takes these and every prop of TextareaProps.
| Prop | Type | Default |
|---|---|---|
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 };