Installation
Install the dependencies
pnpm add cn class-variance-authorityCopy the component
Copy the following files into src/lib/components/ui/textarea.
<script lang="ts">
import { Input as Primitive } from '@sveltery/base/input';
import type { InputProps } from '@sveltery/base/input';
import { cn } from 'cn';
import type { HTMLAttributes, HTMLTextareaAttributes } from 'svelte/elements';
import type { TextareaProps } from './types.js';
let { class: classProp, value = $bindable(), ...props }: TextareaProps = $props();
// A bound remote field's spread carries the input's `type`, which a textarea has no use for.
// The server renders a spread `value` as an attribute, so `value` goes on the textarea itself.
function withoutTypeOrValue(control: HTMLAttributes<HTMLElement>) {
const rest: Record<string, unknown> = { ...control };
delete rest.type;
delete rest.value;
return rest as HTMLTextareaAttributes;
}
</script>
<!-- Base labels, describes and validates its control, so the textarea renders through it. -->
<Primitive {...props as InputProps} bind:value>
{#snippet render(control)}
<textarea data-slot="textarea" {...withoutTypeOrValue(control)} value={(control as HTMLTextareaAttributes).value} class={cn('border-input dark:bg-input/30 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 disabled:bg-input/50 dark:disabled:bg-input/80 rounded-lg border bg-transparent px-2.5 py-2 text-base transition-colors focus-visible:ring-3 aria-invalid:ring-3 md:text-sm flex field-sizing-content min-h-16 w-full outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', classProp)}></textarea>
{/snippet}
</Primitive>import type { HTMLTextareaAttributes } from 'svelte/elements';
/** A textarea holds one value, so `value` takes what a Field control takes. */
export type TextareaProps = Omit<HTMLTextareaAttributes, 'value'> & { value?: string | number | null };export { default as Textarea } from './Textarea.svelte';
export type { TextareaProps } from './types.js';Update the import paths
Change the imports to match your project setup.
Usage
<script lang="ts">
import { Textarea } from '$lib/components/ui/textarea';
</script><Textarea name="message" placeholder="Type your message here." />