Drivn vs shadcn/ui — Textarea Compared
Both Drivn and shadcn/ui ship a dependency-free Textarea. Compare the styling pattern, ref handling, focus ring, and validation behaviour side by side.
Textarea is one of the few components where Drivn and shadcn/ui agree on the basics: neither pulls in Radix, neither ships a runtime UI dependency, and both are a single styled <textarea> you can read in under a minute. So this is not a dependency story — it is a styling-philosophy and defaults story. Drivn's Textarea lives at packages/drivn/src/registry/components/textarea.ts as a React.forwardRef component with every class held in one const styles object. shadcn/ui's Textarea is a plain function component that spreads a data-slot and a long inline cn() class string, relying on React 19's ref-as-prop instead of an explicit forwardRef.
The meaningful differences are what each one gives you by default. Drivn keeps the surface minimal — a vertical-resize textarea with a clean border, a muted placeholder, and disabled styling, much like its single-line Input — and leaves focus rings and validation states for you to add. shadcn ships more out of the box: a focus-visible ring, aria-invalid styling, and field-sizing-content auto-grow. This page walks each difference with verbatim source from the Drivn registry, and is honest about the places shadcn's richer defaults win.
Side-by-side comparison
| Feature | Drivn | shadcn/ui |
|---|---|---|
| Install command | npx drivn add textarea | npx shadcn@latest add textarea |
| Runtime UI dependencies | cn() utility only — zero npm UI packages | cn() only — also dependency-free |
| Styling pattern | Single const styles object | Inline cn() class string in className |
| Ref handling | Explicit React.forwardRef | React 19 ref-as-prop (no forwardRef) |
| Works with react-hook-form | Yes — ref forwards to the textarea | Yes — ref forwards to the textarea |
| Resize behaviour | resize-y — vertical only | field-sizing-content auto-grow |
| Min height | min-h-[80px] | min-h-16 |
| Border radius | rounded-[10px] | rounded-md |
| Focus ring | Yes — focus-visible ring | |
| aria-invalid styling | Yes — destructive ring on invalid | |
| License | MIT | MIT |
One styles object vs one inline class string
Drivn puts every Textarea class in a single const styles object with one base key, built through cn(). You read the whole visual surface top to bottom — sizing, border, text colour, focus, resize, disabled — in five lines, then merge any caller className over it. shadcn/ui keeps the same classes but inlines them directly in the cn() call inside the JSX, alongside a data-slot="textarea" attribute used for styling hooks.
Neither approach adds a dependency, so the choice is about how you prefer to read and edit a component. Drivn's object means restyling is editing one named key; shadcn's inline string means the classes sit right where they are applied. Both end up as the same <textarea> element. See the full surface on the Textarea reference.
1 // packages/drivn/src/registry/components/textarea.ts — verbatim 2 const styles = { 3 base: cn( 4 'w-full min-h-[80px] px-4 py-3', 5 'border border-input rounded-[10px]', 6 'text-foreground placeholder:text-muted-foreground text-sm', 7 'focus:outline-none transition-colors', 8 'resize-y disabled:opacity-50 disabled:cursor-default' 9 ), 10 }
Explicit forwardRef vs React 19 ref-as-prop
Drivn's Textarea is wrapped in React.forwardRef<HTMLTextAreaElement, TextareaProps>, so the ref lands directly on the underlying <textarea>. That is what lets react-hook-form register the field, what gives you imperative focus, and what keeps the component working on React 18 as well as 19. shadcn/ui's current Textarea drops forwardRef entirely and is a plain function that spreads props — it relies on React 19 treating ref as a normal prop.
Functionally the result is the same on React 19: both forward the ref to the textarea, so both work with form libraries and focus management. The difference is compatibility surface — Drivn's explicit forwardRef is the conservative choice that behaves identically across React versions, while shadcn's leaner signature assumes React 19. The props type is just React.TextareaHTMLAttributes<HTMLTextAreaElement>, so every native attribute — rows, maxLength, name, onChange — passes straight through.
1 // packages/drivn/src/registry/components/textarea.ts — verbatim 2 type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement> 3 4 export const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(({ 5 className, 6 ...props 7 }, ref) => ( 8 <textarea 9 ref={ref} 10 className={cn(styles.base, className)} 11 {...props} 12 /> 13 ))
Where shadcn wins: focus ring, validation, auto-grow
Being honest about the defaults: shadcn/ui's Textarea ships three things Drivn leaves to you. It adds a focus-visible ring so keyboard focus is clearly visible, aria-invalid styling that paints a destructive ring when a field is marked invalid, and field-sizing-content so the box auto-grows with the typed content. Drivn's Textarea uses focus:outline-none transition-colors with no ring, relies on the border for focus indication, and uses a fixed min-h-[80px] with resize-y for a user-dragged handle instead of auto-grow.
If you want shadcn's behaviour on the Drivn component, it is a few utility classes away — add focus-visible:ring-2 focus-visible:ring-ring to the styles.base object and an aria-invalid:border-destructive for validation. Because the classes live in one place, you are editing one key rather than hunting through a long inline string. The trade is the usual Drivn trade: a smaller default surface you extend deliberately, versus richer defaults you inherit — the same trade you see across Drivn vs shadcn comparisons.
1 import { Textarea } from "@/components/ui/textarea" 2 3 export default function Page() { 4 return ( 5 <Textarea placeholder="Type your message..." /> 6 ) 7 }
Install Drivn in one command
Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.
npx drivn@latest createRequires Node 18+. Works with npm, pnpm, and yarn.
Frequently asked questions
Neither. Textarea is one of the components where both libraries ship a plain styled <textarea> with no headless primitive. Drivn imports only React and the cn() helper; shadcn/ui also has no Radix dependency for Textarea. The comparison is about styling pattern, ref handling, and default behaviour — not about a dependency in your tree, because there is none on either side.
Yes. Drivn wraps the Textarea in React.forwardRef<HTMLTextAreaElement, TextareaProps>, so the ref lands on the underlying textarea element. That makes it work with react-hook-form register, imperative focus, and any code that needs the DOM node. shadcn/ui drops the explicit forwardRef and relies on React 19 treating ref as a prop, which forwards the ref the same way on React 19.
By design the Drivn Textarea uses focus:outline-none transition-colors and indicates focus through the border rather than a ring. shadcn/ui ships a focus-visible ring out of the box. If you want a ring on the Drivn component, add focus-visible:ring-2 focus-visible:ring-ring to the styles.base object — because all classes live in one place, it is a one-line edit.
Drivn uses resize-y, giving a vertical drag handle and a fixed min-h-[80px] starting height — the user resizes it. shadcn/ui uses field-sizing-content, so the textarea auto-grows to fit the typed content. Both are valid; pick auto-grow when you want the box to follow the content, and resize-y when you want the user to control the height.
Yes. Both type their props as React.TextareaHTMLAttributes<HTMLTextAreaElement>, so rows, maxLength, name, value, onChange, placeholder, and every other native textarea attribute pass straight through. Drivn spreads {...props} onto the textarea after applying its styles, and a caller className is merged over the base with cn() so you can override or extend the defaults.

