Form Controls & Input Widgets

Neon includes standard Material 3 interactive controls with full bi-directional state synchronization over the native platform bridge.


1. TextField

Handles keyboard text entry with decoration, placeholder labels, and change listeners:

TextField(
  key: 'input-email',
  placeholder: 'name@example.com',
  onChanged: (text) {
    print('User typed: $text');
  },
  onSubmitted: (text) {
    print('Form submitted with: $text');
  },
)

2. Switch (Toggle)

Renders as a native Android MaterialSwitch or iOS UISwitch:

Switch(
  key: 'setting-notifications',
  value: _notificationsEnabled,
  onChanged: (bool isChecked) {
    setState(() {
      _notificationsEnabled = isChecked;
    });
  },
)

3. Checkbox

Tri-state and binary check selection control:

Checkbox(
  key: 'terms-agreement-check',
  value: _agreeToTerms,
  onChanged: (bool? newValue) {
    setState(() {
      _agreeToTerms = newValue ?? false;
    });
  },
)

4. Radio<T>

Mutually exclusive option selection with generic type support:

Column(
  children: [
    Radio<String>(
      key: 'radio-theme-light',
      value: 'light',
      groupValue: _selectedTheme,
      onChanged: (val) {
        setState(() => _selectedTheme = val!);
      },
    ),
    Radio<String>(
      key: 'radio-theme-dark',
      value: 'dark',
      groupValue: _selectedTheme,
      onChanged: (val) {
        setState(() => _selectedTheme = val!);
      },
    ),
  ],
)

Note on Radio generic types:
Neon provides an internal selectValue() helper on radio groups to bypass Dart generic type erasure during JSON action serialization.


5. Slider

Continuous value selection control:

Slider(
  key: 'volume-slider',
  value: _volumeLevel,
  min: 0.0,
  max: 100.0,
  onChanged: (double newVolume) {
    setState(() {
      _volumeLevel = newVolume;
    });
  },
)

6. SearchBar & SearchAnchor

Integrated Material 3 search bar with suggestions view:

SearchAnchor(
  builder: (context, controller) {
    return SearchBar(
      key: 'main-search-bar',
      hintText: 'Search Neon widgets...',
      onTap: () => controller.openView(),
    );
  },
  suggestionsBuilder: (context, controller) {
    return [
      ListTile(title: Text('Container'), onTap: () {}),
      ListTile(title: Text('ListView'), onTap: () {}),
      ListTile(title: Text('FilledButton'), onTap: () {}),
    ];
  },
)