RiseUI
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.ts

Disabled

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',
    ),
  ],
)