npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@choice-ui/textarea

v0.0.4

Published

A textarea component for multi-line text input with auto-resize and scroll management

Readme

Textarea

A powerful, accessible textarea component with auto-resizing, manual resize handles, and scroll area integration. It supports multiple visual variants, flexible sizing options, and advanced resize modes for different use cases.

Import

import { Textarea } from "@choice-ui/react"

Features

  • Multiple visual variants for different contexts (default, light, dark, reset)
  • Three resize modes: auto-resize, manual handle resize, and fixed size
  • Integrated scroll area for content that exceeds height limits
  • Row-based size constraints (minRows, maxRows)
  • Selected state for visual emphasis
  • Editing state tracking with callbacks
  • Automatic text selection on focus
  • Disabled and read-only support
  • Password manager protection (data-1p-ignore)
  • Automatic spellcheck and autocomplete disabling
  • Dragging state with visual feedback
  • Performance optimized with memoization

Usage

Basic

<Textarea
  value={value}
  onChange={setValue}
/>

Auto-resize with row constraints

<Textarea
  value={value}
  onChange={setValue}
  resize="auto"
  minRows={3}
  maxRows={10}
/>

Manual resize with handle

<Textarea
  value={value}
  onChange={setValue}
  resize="handle"
  minRows={5}
  maxRows={15}
/>

Fixed size

<Textarea
  value={value}
  onChange={setValue}
  resize={false}
  rows={8}
/>

Variants

// Default - follows page theme
<Textarea variant="default" value={value} onChange={setValue} />

// Light - fixed light appearance
<Textarea variant="light" value={value} onChange={setValue} />

// Dark - fixed dark appearance
<Textarea variant="dark" value={value} onChange={setValue} />

// Reset - no variant styling
<Textarea variant="reset" value={value} onChange={setValue} />

States

<Textarea selected value={value} onChange={setValue} />
<Textarea disabled value={value} onChange={setValue} />
<Textarea readOnly value={value} />

With editing state tracking

<Textarea
  value={value}
  onChange={setValue}
  onIsEditingChange={(isEditing) => {
    console.log("Textarea editing state:", isEditing)
  }}
/>

Props

interface TextareaProps
  extends
    Omit<HTMLProps<HTMLTextAreaElement>, "value" | "onChange" | "size">,
    Pick<TextareaAutosizeProps, "minRows" | "maxRows"> {
  /** Additional CSS class names */
  className?: string

  /** Callback when the textarea value changes */
  onChange?: (value: string) => void

  /** Callback when editing state changes (focus/blur) */
  onIsEditingChange?: (isEditing: boolean) => void

  /** Resize behavior mode */
  resize?: "auto" | "handle" | false

  /** Whether the textarea appears selected/highlighted */
  selected?: boolean

  /** Current textarea value */
  value?: string

  /** Visual style variant of the textarea */
  variant?: "default" | "light" | "dark" | "reset"
}
  • Defaults:

    • variant: "default" (follows page theme)
    • resize: "auto"
    • minRows: 3
    • selected: false
    • spellCheck: false
    • autoComplete: "off"
  • Variant options:

    • default: Follows the page theme dynamically (light/dark mode)
    • light: Fixed light appearance regardless of theme
    • dark: Fixed dark appearance regardless of theme
    • reset: Removes variant styling, no variant settings applied
  • Behavior:

    • Automatically selects all text on focus
    • Tracks editing state and calls onIsEditingChange on focus/blur
    • Cleans up editing state on component unmount
    • Protected from password managers with data-1p-ignore
    • Shows resize cursor during manual resize operations

Resize Modes

Auto (resize="auto")

  • Automatically adjusts height based on content
  • Respects minRows and maxRows constraints
  • Shows scrollbar when content exceeds maxRows

Handle (resize="handle")

  • Shows a resize handle in the bottom-right corner
  • Allows manual height adjustment by dragging
  • Respects minRows and maxRows constraints
  • Provides visual feedback during resizing

Fixed (resize={false})

  • Fixed height based on rows prop
  • No automatic resizing
  • Shows scrollbar when content exceeds height

Styling

  • This component uses Tailwind CSS via tailwind-variants in tv.ts with slots for different parts.
  • Customize using the className prop; classes are merged with the component's internal classes.
  • Slots available in tv.ts: container, textarea, viewport, resizeHandle.
  • Supports dragging state with visual feedback.

Accessibility

  • Supports all standard HTML textarea attributes
  • Proper focus management with visual indicators
  • Compatible with screen readers
  • Keyboard navigation friendly
  • Supports aria-* attributes for enhanced accessibility
  • Resize handle is keyboard accessible

Best practices

  • Choose the appropriate resize mode for your use case:
    • Use auto for dynamic content that grows with user input
    • Use handle when users need control over the display area
    • Use false for fixed-layout designs
  • Set reasonable minRows and maxRows to prevent extreme sizes
  • Use the selected state to highlight important or active textareas
  • Handle editing state changes to provide user feedback
  • Consider using readOnly instead of disabled when the content should remain visible but not editable

Examples

Auto-resizing comment field

const [comment, setComment] = useState("")

<Textarea
  value={comment}
  onChange={setComment}
  resize="auto"
  minRows={2}
  maxRows={8}
  placeholder="Write your comment..."
/>

Code editor with manual resize

const [code, setCode] = useState("")

<Textarea
  value={code}
  onChange={setCode}
  resize="handle"
  minRows={10}
  maxRows={30}
  placeholder="Enter your code..."
  className="font-mono"
/>

Fixed-size message box

const [message, setMessage] = useState("")

<Textarea
  value={message}
  onChange={setMessage}
  resize={false}
  rows={6}
  placeholder="Enter your message..."
/>

Dark theme with editing state

const [content, setContent] = useState("")
const [isEditing, setIsEditing] = useState(false)

<div className="space-y-2">
  <Textarea
    variant="dark"
    value={content}
    onChange={setContent}
    onIsEditingChange={setIsEditing}
    resize="auto"
    minRows={4}
    placeholder="Start typing..."
  />
  {isEditing && (
    <div className="text-body-small text-white/60">
      Currently editing...
    </div>
  )}
</div>

Performance Notes

  • The component uses useMemo and useEventCallback for optimal performance
  • Height calculations are cached to prevent unnecessary recalculations
  • Constants are extracted to avoid redeclaration on re-renders
  • Drag event listeners are properly cleaned up to prevent memory leaks

Notes

  • The component integrates with ScrollArea for smooth scrolling behavior
  • Manual resize operations show visual feedback with dashed borders
  • The cursor changes to ns-resize during drag operations for better UX
  • All resize modes respect accessibility guidelines and keyboard navigation