Skip to content

Text area

In review
Live · web

Interactive: type, watch the counter

States: disabled, read-only

// Web: React, consuming @dizyx/nockerl-tokens. (Web is the laggard platform; this is the
// canonical API the published @dizyx/nockerl-react package exposes. The shipped shadcn
// textarea.tsx is being conformed to it; see the drift note below.)
import { NockerlTextArea } from '@dizyx/nockerl-react';
export function TaskPrompt() {
const [prompt, setPrompt] = useState('');
return (
<NockerlTextArea
label="Task instructions"
value={prompt}
onChange={setPrompt}
placeholder="Describe what the agent should do…"
helperText="The agent runs with these instructions."
maxLength={2000}
minRows={3}
maxRows={12}
/>
);
}
PropTypeDefaultDescription
label *stringPersistent label, bound to the field via htmlFor / id. Never a placeholder.
value *stringCurrent value (controlled).
onChange(value: string) => voidChange handler. Ignored while disabled or read-only.
placeholderstringGhost prompt INSIDE the well. It is supplementary, never the label.
helperTextstringHelper text under the well. Replaced by errorText / statusText when set.
errorTextstringWhen set, the area renders its error treatment (red border + this message).
statusFieldStatusThe validation ladder: warning / success (or error) border + a matching, icon-carrying help line showing statusText. errorText (and an over-cap counter) still win if set. Color is never the only signal. A glyph rides along.
statusTextstringThe message shown for status (ignored when errorText / over-cap wins).
requiredbooleanfalseMarks the field required: renders the status-colored * after the label.
disabledbooleanfalseInert + clearly-seen (never invisible).
readOnlybooleanfalseValue shown, selectable, not editable.
maxLengthnumberOptional max length; drives the character counter + over-cap error.
minRowsnumber3Rows the field starts at before it auto-grows.
maxRowsnumber8Rows it grows to before it starts scrolling instead.

Also accepts the native <textarea> attributes (e.g. onClick, disabled, id, aria-*, data-*), forwarded straight through, plus a forwarded ref.

Cross-platform drift (tracked for reconciliation)

The recessed-well spec is the target; these are the real divergences between the shipped platforms, tracked in the Review queue:

  • No single shared component: each platform reaches the area by its own route. Web exposes NockerlTextArea from @dizyx/nockerl-react; Voice has the shared .nockerlFieldWell() modifier (reused for multi-line); Android repeats OutlinedTextField inline. A common extraction with a bundled counter is still owed.
  • Recessed vs outlined: Voice + the spec are recessed wells; Android’s OutlinedTextField is an outlined box (no inset). It should adopt the inset surface.
  • Control radius: Voice hardcodes 8pt; Android uses the 12dp token; web’s shadcn textarea is rounded-md (6px). The well must be the 12px control radius everywhere.
  • Counter: only web (canonical) bundles the current / max counter + over-cap error. Android/Voice render it manually (or omit it). It should be a first-class prop.
  • Auto-grow: web (JS), Compose (maxLines), and Swift (.lineLimit) each auto-grow, but via three different mechanisms; behavior is aligned, implementation is not.