Components
TextField
HeroUI TextField shell — textfield.css column layout, Label + Input/TextArea + Description + FieldError.
Usage
Email-style field with label and placeholder.
const RiseTextField(
fullWidth: true,
keyboardType: TextInputType.emailAddress,
labelText: 'Email',
placeholder: 'Enter your email',
)With description
Helper text under the input.
const RiseTextField(
labelText: 'Username',
placeholder: 'juliam_example',
helperText: 'Choose a unique username for your account.',
)Required field
Required marker with helper text.
const RiseTextField(
isRequired: true,
labelText: 'Full name',
helperText: 'This field is required.',
)Validation
Invalid state hides helper and shows error.
RiseTextField(
controller: controller,
labelText: 'Bio',
minLines: 2,
maxLines: 4,
isInvalid: invalid,
errorText: invalid ? 'Minimum 20 characters required.' : null,
helperText: invalid ? null : 'Minimum 20 characters (${text.length}/20).',
onChanged: (_) => setState(() {}),
)Controlled
Synced values and character counts.
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RiseTextField(
controller: nameController,
labelText: 'Display name',
onChanged: (_) => setState(() {}),
),
Text('Characters: ${nameController.text.length}'),
RiseTextField(
controller: bioController,
labelText: 'Bio',
minLines: 2,
maxLines: 5,
maxLength: 200,
onChanged: (_) => setState(() {}),
),
Text('Characters: ${bioController.text.length} / 200'),
],
)Error message
Static invalid state with FieldError-style copy.
const RiseTextField(
keyboardType: TextInputType.emailAddress,
labelText: 'Email',
placeholder: 'you@example.com',
isInvalid: true,
errorText: 'Please enter a valid email address.',
)Invalid
Story `Invalid`: password + address errors (description hidden).
// Missing code for slug "invalid" in showcase-code-maps.tsDisabled
Non-editable field with helper text.
const RiseTextField(
labelText: 'Account ID',
hintText: 'acct_01H…',
helperText: 'This field cannot be edited.',
enabled: false,
)Multiline
Several rows inside the same TextField API.
const RiseTextField(
labelText: 'Message',
placeholder: 'How can we help?',
helperText: 'Maximum 500 characters.',
minLines: 3,
maxLines: 6,
maxLength: 500,
)Input types
Password, numeric, and email keyboards.
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const RiseTextField(
labelText: 'Password',
obscureText: true,
placeholder: '••••••••',
),
RiseTextField(
labelText: 'Age',
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
placeholder: '25',
),
const RiseTextField(
labelText: 'Email',
keyboardType: TextInputType.emailAddress,
placeholder: 'name@domain.com',
),
],
)Full width
Stacked fields that stretch to the container.
const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RiseTextField(
fullWidth: true,
labelText: 'Your name',
placeholder: 'Ada Lovelace',
),
RiseTextField(
fullWidth: true,
labelText: 'Password',
obscureText: true,
helperText: 'Password must be longer than 8 characters.',
placeholder: '••••••••',
),
],
)In surface
Default card (`bg-surface`, same fill token as primary fields) + secondary inputs.
const RiseCard(
variant: RiseCardVariant.default_,
padding: EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RiseTextField(
fullWidth: true,
variant: RiseTextFieldVariant.secondary,
labelText: 'Your name',
helperText: "We'll never share this with anyone else.",
placeholder: 'Jane Doe',
),
RiseTextField(
fullWidth: true,
variant: RiseTextFieldVariant.secondary,
labelText: 'Email',
keyboardType: TextInputType.emailAddress,
placeholder: 'you@example.com',
),
RiseTextField(
fullWidth: true,
variant: RiseTextFieldVariant.secondary,
labelText: 'Bio',
helperText: 'Minimum 4 rows.',
minLines: 4,
maxLines: 8,
placeholder: 'Tell us about yourself…',
),
],
),
);Variants
Primary vs secondary field fill.
const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RiseTextField(
fullWidth: true,
variant: RiseTextFieldVariant.primary,
labelText: 'Primary',
placeholder: 'Surface container fill',
),
RiseTextField(
fullWidth: true,
variant: RiseTextFieldVariant.secondary,
labelText: 'Secondary',
placeholder: 'Muted fill — use on surfaces',
),
],
)