TextField
An intelligent input component built on MUI TextField. Supports standalone usage, seamless DashForm integration with automatic field binding, validation error gating, and reactive visibility. The foundation for composed field behaviors.
Quick Start
Copy & Paste
import { TextField } from '@dashforge/ui';
<TextField label="Email" name="email" />Examples
Common TextField patterns and configurations
Basic
A simple text field with a label
<TextField label="Name" name="name" />
Disabled
A disabled text field
<TextField label="Name" name="name" disabled />
Error State
A text field displaying an error
Invalid email
<TextField label="Email" name="email" error helperText="Invalid email" />
Full Width
A text field that spans the full width
<TextField label="Address" name="address" fullWidth />
Inline Layout
A text field with label on the left
<TextField label="Email" name="email" layout="inline" fullWidth />
Inline with Helper Text
Inline layout with helper text below control
Must be unique
<TextField label="Username" name="username" layout="inline" helperText="Must be unique" fullWidth />
Multiline
A text field with multiple lines
<TextField
label="Description"
name="description"
multiline
rows={4}
/>Layout Variants
Floating, stacked, and inline label layouts
TextField supports three layout modes: floating (default), stacked, and inline. The layout prop controls label positioning and composition independently of the MUI variant (outlined/filled/standard).
Floating (Default)
We will never share your email.
<TextField label="Email" name="email" placeholder="Enter your email" helperText="We will never share your email." fullWidth />
What to observe: Standard MUI floating label behavior. Label animates up when field is focused or has value. This is the migration-friendly default.
Stacked Layout
We will never share your email.
<TextField label="Email" name="email" placeholder="Enter your email" helperText="We will never share your email." layout="stacked" fullWidth />
What to observe: External label above input field. Label is always visible and stationary. Helper text appears below the input.
Inline Layout
We will never share your email.
<TextField label="Email" name="email" placeholder="Enter your email" helperText="We will never share your email." layout="inline" fullWidth />
What to observe: External label to the left of input field, aligned to the top. Helper text appears below the input. Useful for compact horizontal forms.
Layout Architecture
Floating layout (default): Uses standard MUI TextField composition with internal floating label. This preserves the familiar MUI behavior and ensures easy migration.
Custom layouts (stacked/inline): Use an internal FieldLayoutShell component to manage external label and helper text positioning. The shell renders labels and helper text outside MUI TextField while preserving all Dashforge capabilities (form integration, validation, conditional visibility, etc.).
Spacing values for custom layouts are defined in the theme's fieldLayout configuration, ensuring consistency across all form-connected components (TextField, Select, Autocomplete, etc.).
Layout with Error State
Invalid email format
<TextField label="Email" name="email" error helperText="Invalid email format" fullWidth />
Invalid email format
<TextField label="Email" name="email" layout="stacked" error helperText="Invalid email format" fullWidth />
Invalid email format
<TextField label="Email" name="email" layout="inline" error helperText="Invalid email format" fullWidth />
What to observe: Error states work identically across all layouts. Labels turn red and helper text displays error messages with appropriate styling.
Interactive Playground
Experiment with props and see live results
Live Playground
Helper text
tsx
<TextField label="Name" placeholder="Enter your name" helperText="Helper text" name="fieldName" />
Dashforge Capabilities
Progressive adoption from controlled components to predictive forms
Use TextField as a controlled component, integrate with React Hook Form, or leverage reactive capabilities. Choose the adoption level that fits your workflow.
Controlled
Available Now
Works as a standard React controlled component. No proprietary lock-in—use familiar patterns.
Standard value and onChange props
Low adoption friction for existing codebases
Suitable for incremental migration
<TextField
value={name}
onChange={(e) => setName(e.target.value)}
label="Name"
/>React Hook Form Ready
Integration-Friendly
Integrates with React Hook Form via DashForm. Automatic validation, error handling, and familiar RHF patterns.
Works with RHF through DashFormBridge
Automatic validation and error handling
Supports gradual adoption without rewrites
<DashForm>
<TextField
name="email"
label="Email"
/>
</DashForm>Reactive Visibility
Available Now
Conditional rendering via visibleWhen. Fields respond to form state changes without manual orchestration.
Conditional rendering via visibleWhen
Engine evaluates the predicate
Useful for dependent text fields
<TextField
name="other"
label="Other"
visibleWhen={(engine) =>
engine.getNode('category')?.value === 'other'
}
/>Access Control (RBAC)
Control field visibility and interaction based on user permissions. Fields can be hidden, disabled, or readonly when users lack access.
Hide when unauthorized
<TextField
name="salary"
access={{
resource: 'user.salary',
action: 'read',
onUnauthorized: 'hide',
}}
/>Disable when cannot edit
<TextField
name="status"
access={{
resource: 'user.status',
action: 'update',
onUnauthorized: 'disable',
}}
/>Readonly for view-only
<TextField
name="email"
access={{
resource: 'user.email',
action: 'update',
onUnauthorized: 'readonly',
}}
/>Combined with visibleWhen
<TextField
name="other"
visibleWhen={(engine) =>
engine.getNode('category')?.value === 'other'
}
access={{
resource: 'form.other',
action: 'read',
onUnauthorized: 'hide',
}}
/>Note: When combining visibleWhen with RBAC, both conditions must be satisfied. The field shows only if UI logic returns true AND the user has required permissions.
Form Integration
Real-world scenarios with React Hook Form and dynamic visibility
Live scenarios showing DashForm integration and reactive visibility in real form contexts.
React Hook Form Integration
Try it: Type in the fields and submit the form
TextField integrates seamlessly with React Hook Form through DashForm. Fields self-register, errors display after blur, and validation follows RHF patterns. Try submitting with empty fields or invalid email.
import { DashForm } from '@dashforge/forms';
import { TextField } from '@dashforge/ui';
function RegistrationForm() {
const handleSubmit = (data: FormData) => {
console.log('Submitted:', data);
};
return (
<DashForm
defaultValues={{ firstName: '', email: '' }}
onSubmit={handleSubmit}
mode="onBlur"
>
<TextField
name="firstName"
label="First Name"
rules={{ required: 'Name is required' }}
/>
<TextField
name="email"
label="Email"
rules={{
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address'
}
}}
/>
<button type="submit">Submit</button>
</DashForm>
);
}
// TextField automatically:
// - Registers with React Hook Form
// - Syncs value from form state
// - Displays validation errors when touched
// - Tracks dirty/touched stateWhy it matters
Drop TextField into existing form architectures without rewriting validation or state management.
Reactive Conditional Visibility
Try it: Select a contact method and watch fields appear
TextField supports conditional rendering through visibleWhen. Fields render based on engine state—query field values and make rendering decisions. Select "Email" or "Phone" to see conditional fields appear without manual state orchestration.
import { DashForm } from '@dashforge/forms';
import { TextField, Select } from '@dashforge/ui';
function ContactForm() {
return (
<DashForm defaultValues={{ contactMethod: '', phone: '', email: '' }}>
<Select
name="contactMethod"
label="Preferred Contact Method"
options={[
{ label: 'Email', value: 'email' },
{ label: 'Phone', value: 'phone' }
]}
/>
{/* Email field: renders only when email is selected */}
<TextField
name="email"
label="Email Address"
rules={{ required: 'Email is required' }}
visibleWhen={(engine) => {
const node = engine.getNode('contactMethod');
return node?.value === 'email';
}}
/>
{/* Phone field: renders only when phone is selected */}
<TextField
name="phone"
label="Phone Number"
rules={{ required: 'Phone is required' }}
visibleWhen={(engine) => {
const node = engine.getNode('contactMethod');
return node?.value === 'phone';
}}
/>
</DashForm>
);
}
// The Engine API provides:
// - getNode(name): Access any field's state
// - Component re-renders on dependency changes
// - Component makes rendering decision (engine provides state)Why it matters
Build adaptive forms where field visibility responds to user input. Define the predicate—the component handles rendering.
API Reference
Complete props and type definitions
Explicit vs Auto-Bound Props: When inside DashForm, TextField receives value, error, helperText, onChange, and onBlur automatically through field binding. Explicit props always take precedence over form-provided values.
| Prop | Type | Default | Description |
|---|---|---|---|
| name | string | - | Field name for form integration (required) |
| label | string | - | Label text displayed above the input |
| value | string | - | Controlled value of the input |
| onChange | (event) => void | - | Callback fired when the value changes |
| error | boolean | false | If true, displays error state. Explicit error prop overrides form-provided error state. When inside DashForm without explicit prop, error is gated (shows only when touched OR submitted). |
| helperText | string | - | Helper text displayed below input. Explicit helperText prop overrides form-provided validation error message. When inside DashForm, validation errors display as helperText (gated by touched/submitted state). |
| disabled | boolean | false | If true, the input is disabled |
| fullWidth | boolean | false | If true, the input takes up the full width of its container |
| multiline | boolean | false | If true, the input becomes a textarea |
| rows | number | - | Number of rows to display when multiline is true |
| layout | 'floating' | 'stacked' | 'inline' | 'floating' | Field layout mode. floating: standard MUI floating label (internal). stacked: external label above control. inline: external label to left of control. Layout is architectural, not just styling. |
| rules | ValidationRules | - | Validation rules for DashForm integration. Format follows React Hook Form rules contract. Only used when inside DashForm—ignored in standalone mode. |
| visibleWhen | (engine: Engine) => boolean | - | Component-level conditional rendering predicate. Receives engine instance with access to all field state via getNode(name). When false, component renders null. Re-evaluates on dependency changes. Only works inside DashForm (requires engine). |
Under the hood
How TextField behaves and why it works this way
Form integration
Automatically binds to form state inside DashForm. No Controller, no manual wiring. Works as a standard MUI TextField when used standalone.
Behavior model
Errors appear only after blur or submit. Fields can react to form state using visibleWhen. No manual orchestration required.
Architecture
Built on top of MUI TextField. Fully typed with TypeScript. Designed as a foundation for composed form behaviors.