Skip to content
Drivn
4 min read

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

FeatureDrivnshadcn/ui
Install commandnpx drivn add textareanpx shadcn@latest add textarea
Runtime UI dependenciescn() utility only — zero npm UI packagescn() only — also dependency-free
Styling patternSingle const styles objectInline cn() class string in className
Ref handlingExplicit React.forwardRefReact 19 ref-as-prop (no forwardRef)
Works with react-hook-formYes — ref forwards to the textareaYes — ref forwards to the textarea
Resize behaviourresize-y — vertical onlyfield-sizing-content auto-grow
Min heightmin-h-[80px]min-h-16
Border radiusrounded-[10px]rounded-md
Focus ringYes — focus-visible ring
aria-invalid stylingYes — destructive ring on invalid
LicenseMITMIT

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
2const 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
2type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>
3
4export 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.

1import { Textarea } from "@/components/ui/textarea"
2
3export default function Page() {
4 return (
5 <Textarea placeholder="Type your message..." />
6 )
7}
Get started

Install Drivn in one command

Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.

npx drivn@latest create

Requires Node 18+. Works with npm, pnpm, and yarn.

Enjoying Drivn?
Star the repo on GitHub to follow new component releases.
Star →

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.