react ~4 KB 0 deps v0.1.0 ↗ GitHub ↗

@mshafiqyajid/react-textarea

Headless textarea hook + styled component. Auto-resize (min/max rows), character counter (inside or outside), three sizes, four tones, hint and error messages, controlled or uncontrolled.

Playground #

Enter your message
Props
TSX
import { TextareaStyled } from "@mshafiqyajid/react-textarea/styled";
import "@mshafiqyajid/react-textarea/styles.css";

<TextareaStyled
  placeholder="Type something..."
/>

Install #

npm install @mshafiqyajid/react-textarea

Quick start #

import { TextareaStyled } from "@mshafiqyajid/react-textarea/styled";
import "@mshafiqyajid/react-textarea/styles.css";

<TextareaStyled
  label="Message"
  placeholder="Type your message..."
  maxLength={500}
  showCount
/>

Auto-resize #

autoResize is enabled by default. The textarea grows from minRows (default: 2) up to maxRows (default: 10) as the user types. Set autoResize={false} to disable and use resize instead.

<TextareaStyled
  label="Notes"
  minRows={3}
  maxRows={8}
  autoResize
  placeholder="The textarea grows as you type..."
/>

{/* Manual resize */}
<TextareaStyled
  label="Bio"
  autoResize={false}
  resize="vertical"
  rows={4}
/>

Character count #

Enable showCount with an optional maxLength. The counter can be positioned inside or outside the textarea. It turns amber when at the limit and red when over.

{/* Count outside (default) */}
<TextareaStyled
  label="Bio"
  maxLength={160}
  showCount
/>

{/* Count inside */}
<TextareaStyled
  label="Comment"
  maxLength={280}
  showCount
  countPosition="inside"
/>

Validation states #

Pass an error string to flip to the danger tone and render the message below. Use hint for plain helper text.

<TextareaStyled
  label="Description"
  value={text}
  onChange={(e) => setText(e.target.value)}
  error={text.length < 20 ? "Must be at least 20 characters" : undefined}
  hint="Describe your project in a few sentences"
/>

Controlled #

const [value, setValue] = useState("");

<TextareaStyled
  value={value}
  onChange={(e) => setValue(e.target.value)}
  onValueChange={(v) => console.log(v)}
  label="Message"
  maxLength={200}
  showCount
/>

Headless #

Use useTextarea for full control over markup and styling. The hook manages value state, ARIA attributes, and character counting.

import { useTextarea } from "@mshafiqyajid/react-textarea";

const { textareaProps, charCount, isAtLimit, isOverLimit } = useTextarea({
  defaultValue: "",
  maxLength: 200,
  required: true,
});

return (
  <div>
    <label htmlFor={textareaProps.id}>Message</label>
    <textarea {...textareaProps} placeholder="Type something..." />
    <span style={{ color: isOverLimit ? "red" : "inherit" }}>
      {charCount} / 200
    </span>
  </div>
);

API — TextareaStyled #

PropTypeDefaultDescription
valuestringControlled value
defaultValuestring""Uncontrolled initial value
onChange(e: ChangeEvent) => voidNative change event handler
onValueChange(value: string) => voidCalled with the string value on every change
placeholderstringPlaceholder text
rowsnumber3Row count when autoResize is false
minRowsnumber2Minimum rows when auto-resizing
maxRowsnumber10Maximum rows when auto-resizing
autoResizebooleantrueAutomatically grow/shrink the textarea
maxLengthnumberMaximum character count
showCountbooleanfalseShow character counter
countPosition"inside" | "outside""outside"Where to render the counter
resize"none" | "vertical" | "horizontal" | "both""none"CSS resize when autoResize is false
size"sm" | "md" | "lg""md"Size variant
tone"neutral" | "primary" | "success" | "danger""neutral"Colour tone
labelstringField label rendered above
hintstringHelper text rendered below
errorstringError message — auto-applies danger tone
requiredbooleanfalseMark field as required (adds asterisk)
disabledbooleanfalseDisable the textarea
readOnlybooleanfalseMake the textarea read-only
invalidbooleanfalseForce invalid state without inline error text
idstringautoHTML id for the textarea
namestringForm field name
autoFocusbooleanAuto-focus on mount
spellCheckbooleanBrowser spell-check
classNamestringExtra class on the root element
styleCSSPropertiesInline style on the root element

API — useTextarea hook #

OptionTypeDefaultDescription
valuestringControlled value
defaultValuestring""Uncontrolled initial value
onChange(e: ChangeEvent) => voidNative change event
onValueChange(value: string) => voidString value change handler
maxLengthnumberCharacter limit for isAtLimit / isOverLimit
disabledbooleanDisabled state
readOnlybooleanRead-only state
requiredbooleanRequired state
invalidbooleanInvalid state
idstringautoHTML id
namestringForm name

Returns { textareaProps, charCount, isAtLimit, isOverLimit }. Spread textareaProps on a <textarea> element.

Edit this page on GitHub