# V textarea 10

> Support ticket with category chips and message field

A shadcn/ui block from the [@cnippet](https://ui.cnippet.dev/) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/cnippet/v-textarea-10).

- Page, with a live preview: https://shadcn.exchange/r/cnippet/v-textarea-10
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/cnippet/v-textarea-10-light-de89bd9965275f76.png
- Registry item: https://ui.cnippet.dev/r/v-textarea-10.json
- Categories: textarea
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://ui.cnippet.dev/r/v-textarea-10.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `@cnippet/textarea`

## Files

### `registry/default/variants/v-textarea-10.tsx`

```tsx
"use client";

import type { FormEvent } from "react";
import { useState } from "react";
import { Button } from "@/registry/default/ui/button";
import { Field, FieldLabel } from "@/registry/default/ui/field";
import { Textarea } from "@/registry/default/ui/textarea";

const categories = [
  "Bug Report",
  "Feature Request",
  "Billing",
  "Account",
  "Other",
];

export function Pattern() {
  const [category, setCategory] = useState("");
  const [message, setMessage] = useState("");
  const [sent, setSent] = useState(false);
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault();
    setLoading(true);
    await new Promise((r) => setTimeout(r, 700));
    setLoading(false);
    setSent(true);
  };

  if (sent) {
    return (
      <div className="flex w-full max-w-xs flex-col items-center gap-3 rounded-xl border border-border p-6 text-center">
        <div className="flex size-10 items-center justify-center rounded-full bg-emerald-500/10">
          <span className="text-emerald-500 text-xl">✓</span>
        </div>
        <p className="font-semibold text-sm">Ticket submitted!</p>
        <p className="text-muted-foreground text-xs">
          We'll get back to you within 24 hours.
        </p>
        <Button
          onClick={() => {
            setSent(false);
            setCategory("");
            setMessage("");
          }}
          size="sm"
          variant="outline"
        >
          Submit another
        </Button>
      </div>
    );
  }

  return (
    <form
      className="flex w-full max-w-xs flex-col gap-4"
      onSubmit={handleSubmit}
    >
      <Field>
        <FieldLabel>Category</FieldLabel>
        <div className="flex flex-wrap gap-1.5">
          {categories.map((c) => (
            <button
              className={`rounded-full border px-3 py-1 text-xs transition-colors ${
                category === c
                  ? "border-primary bg-primary text-primary-foreground"
                  : "border-input bg-background text-muted-foreground hover:border-ring"
              }`}
              key={c}
              onClick={() => setCategory(c)}
              type="button"
            >
              {c}
            </button>
          ))}
        </div>
      </Field>

      <Field>
        <FieldLabel>Message</FieldLabel>
        <Textarea
          minLength={10}
          onChange={(e) => setMessage(e.target.value)}
          placeholder="Describe your issue in detail…"
          required
          value={message}
        />
        <p className="text-right text-muted-foreground text-xs">
          {message.length} / 500
        </p>
      </Field>

      <Button disabled={!category || loading} loading={loading} type="submit">
        Submit Ticket
      </Button>
    </form>
  );
}
```
