# WFormSelect
A Wind-styled single or multi-select dropdown that integrates seamlessly with Flutter's Form validation. It wraps the core `WSelect` widget with `FormField` logic, providing labels, hint text, and automatic error state handling.
- [Basic Usage](#basic-usage)
- [Constructor](#constructor)
- [Props](#props)
- [Layout Modes](#layout-modes)
- [Event Handling](#event-handling)
- [State Variants](#state-variants)
- [Styling Examples](#styling-examples)
- [All Supported Classes](#all-supported-classes)
- [Customizing Theme](#customizing-theme)
- [Related Documentation](#related-documentation)
```dart
WFormSelect(
label: 'Country',
placeholder: 'Select your country',
options: [
SelectOption(value: 'us', label: 'United States'),
SelectOption(value: 'uk', label: 'United Kingdom'),
],
className: 'w-full border rounded-lg error:border-red-500',
validator: (value) => value == null ? 'Please select a country' : null,
)
```
## Basic Usage
The `WFormSelect` (and its counterpart `WFormMultiSelect`) is designed to be used inside a `Form` widget. It automatically manages its own state and displays validation errors using the `error:` utility prefix when validation fails.
```dart
Form(
key: _formKey,
child: Column(
children: [
WFormSelect(
value: _selectedValue,
options: myOptions,
onChange: (v) => setState(() => _selectedValue = v),
label: 'Select Category',
validator: (v) => v == null ? 'Required' : null,
),
WButton(
onTap: () {
if (_formKey.currentState!.validate()) {
// Process form
}
},
child: WText('Submit'),
),
],
),
)
```
## Constructor
### WFormSelect
```dart
WFormSelect({
Key? key,
T? value,
String? Function(T?)? validator,
void Function(T?)? onSaved,
AutovalidateMode? autovalidateMode,
bool enabled = true,
required List> options,
ValueChanged? onChange,
String placeholder = 'Select an option',
String? className,
String? menuClassName,
bool searchable = false,
String? label,
String? hint,
bool showError = true,
// ... other WSelect props
})
```
### WFormMultiSelect
```dart
WFormMultiSelect({
Key? key,
List? values,
String? Function(List?)? validator,
void Function(List?)? onSaved,
required List> options,
ValueChanged>? onMultiChange,
String placeholder = 'Select options',
String? label,
String? hint,
// ... other multi-select props
})
```
## Props
| Prop | Type | Default | Description |
|:-----|:-----|:--------|:------------|
| `className` | `String?` | `null` | Wind utility classes for the select trigger. |
| `options` | `List>` | **Required** | The list of available options to display. |
| `value` | `T?` | `null` | The currently selected value (single select). |
| `values` | `List?` | `[]` | The currently selected values (multi select). |
| `label` | `String?` | `null` | Optional label text displayed above the select. |
| `hint` | `String?` | `null` | Optional hint text displayed below the select. |
| `validator` | `String? Function(T?)?` | `null` | Form validation logic. |
| `showError` | `bool` | `true` | Whether to display the error message when invalid. |
| `searchable` | `bool` | `false` | Enables a search input inside the dropdown. |
| `disabled` | `bool` | `false` | Disables user interaction. |
| `labelClassName`| `String` | `text-sm font-medium...` | Styling for the label text. |
| `errorClassName`| `String` | `text-red-500 text-xs...` | Styling for the error message. |
## Layout Modes
`WFormSelect` always uses a vertical `flex-col` layout to stack the label, the select trigger, and the error/hint text.
### Standard Stack
By default, the widget arranges elements in a clean vertical flow.
```dart
WFormSelect(
label: 'Department',
hint: 'Choose your primary department',
options: departments,
className: 'border p-3 rounded-md',
)
```
## Event Handling
`WFormSelect` provides standard Form event handlers alongside the select-specific change callbacks.
```dart
WFormSelect(
options: options,
onChange: (value) {
print('Selected: $value');
},
onSaved: (value) {
// Called when FormState.save() is invoked
_formData.dept = value;
},
validator: (value) {
if (value == null) return 'Selection required';
return null;
},
)
```
## State Variants
Since `WFormSelect` injects the `error` state into the underlying `WSelect`, you can use the `error:` prefix to change the styling when validation fails.
```dart
WFormSelect(
className: 'border-gray-300 focus:border-blue-500 error:border-red-500 error:bg-red-50',
options: options,
validator: (v) => v == null ? 'Error' : null,
)
```
## Styling Examples
### Multi-Select Form Field
The `WFormMultiSelect` variation handles lists of values and provides a different set of styling options for selected chips.
```dart
WFormMultiSelect(
label: 'Interests',
values: _selectedInterests,
options: interestOptions,
className: 'border-2 rounded-xl p-2',
onMultiChange: (vals) => setState(() => _selectedInterests = vals),
validator: (vals) => vals!.isEmpty ? 'Select at least one' : null,
)
```
### Searchable Form Select
Perfect for long lists of options where users need to filter quickly.
```dart
WFormSelect(
label: 'User',
searchable: true,
searchPlaceholder: 'Search by name...',
options: users,
className: 'w-full px-4 py-3 bg-white border',
)
```
## All Supported Classes
Since `WFormSelect` wraps `WSelect`, it supports all standard Wind utilities on the `className` and `menuClassName` props.
| Category | Classes |
|:---------|:--------|
| Sizing | `w-full`, `max-w-md`, `h-12` |
| Spacing | `p-{n}`, `px-{n}`, `py-{n}`, `m-{n}` |
| Borders | `border`, `rounded-{size}`, `ring-{n}` |
| Colors | `bg-{color}`, `text-{color}`, `border-{color}` |
| States | `hover:`, `focus:`, `disabled:`, `error:` |
## Customizing Theme
You can globally customize the default styling of form labels and error messages through `WindThemeData`.
```dart
WindThemeData(
// Customizing default form select behavior via theme defaults
)
```
## Related Documentation
- [WSelect - Core Dropdown Widget](./w-select.md)
- [WFormInput - Validated Text Input](./w-form-input.md)
- [WFormCheckbox - Validated Checkbox](./w-form-checkbox.md)
- [Forms in Wind](../core-concepts/forms.md)