search ESC

Searching…

No results for "".

Type at least 2 characters to search.

Docs

WSelect

A highly customizable, utility-first select component that supports single selection, multi-selection, searching, and remote data fetching.

WSelect(
  value: _selected,
  options: [
    SelectOption(value: 'dart', label: 'Dart'),
    SelectOption(value: 'flutter', label: 'Flutter'),
  ],
  onChange: (value) => setState(() => _selected = value),
  className: 'w-64 bg-white border border-gray-300 rounded-lg',
)

Basic Usage

The WSelect widget replaces the standard Material Dropdown with a utility-first approach. It manages its own open state while providing a controlled interface for selection.

WSelect(
  placeholder: 'Choose a number',
  options: List.generate(5, (i) => SelectOption(value: i, label: 'Option $i')),
  onChange: (val) => print('Selected: $val'),
  className: 'bg-white border p-3 rounded-md',
)

Constructor

const WSelect({
  Key? key,
  T? value,
  ValueChanged? onChange,
  bool isMulti = false,
  List? values,
  ValueChanged>? onMultiChange,
  SelectedChipBuilder? selectedChipBuilder,
  required List> options,
  bool searchable = false,
  Future>> Function(String)? onSearch,
  String searchPlaceholder = 'Search...',
  Future> Function(String)? onCreateOption,
  CreateOptionBuilder? createOptionBuilder,
  Future>> Function()? onLoadMore,
  bool hasMore = false,
  String? className,
  String? menuClassName,
  String placeholder = 'Select an option',
  bool disabled = false,
  double? menuWidth,
  double maxMenuHeight = 300,
  Set? states,
  SelectTriggerBuilder? triggerBuilder,
  MultiSelectTriggerBuilder? multiTriggerBuilder,
  SelectItemBuilder? itemBuilder,
  EmptyStateBuilder? emptyBuilder,
  LoadingBuilder? loadingBuilder,
})

Props

Prop Type Default Description
className String? null Utility classes for the trigger container
menuClassName String? null Utility classes for the dropdown menu
options List> Required List of items to display
value T? null Selected value in single-select mode
onChange ValueChanged? null Callback for single selection changes
isMulti bool false Enables multi-select mode
values List? null Selected values in multi-select mode
onMultiChange ValueChanged>? null Callback for multi-selection changes
searchable bool false Shows a search input in the menu
searchPlaceholder String 'Search...' Placeholder text in the search input
onSearch Future>> Function(String)? null Async remote search handler; returns filtered options for the query
onCreateOption Future> Function(String)? null Tagging handler; called when the user creates a new option from search input
createOptionBuilder CreateOptionBuilder? null Custom builder for the "create new option" row in the menu
onLoadMore Future>> Function()? null Pagination handler; called when the user scrolls past the current list
hasMore bool false When true, indicates more pages are available for onLoadMore
placeholder String 'Select an option' Text shown when no value is selected
disabled bool false Prevents interaction
menuWidth double? null Fixed dropdown width; defaults to the trigger width
maxMenuHeight double 300 Maximum height of the dropdown list
states Set? null Custom states for dynamic styling
triggerBuilder SelectTriggerBuilder? null Custom trigger renderer for single-select
multiTriggerBuilder MultiSelectTriggerBuilder? null Custom trigger renderer for multi-select
selectedChipBuilder SelectedChipBuilder? null Custom chip renderer for selected items in multi-select
itemBuilder SelectItemBuilder? null Custom renderer for each option in the menu
emptyBuilder EmptyStateBuilder? null Custom widget when no options match the search
loadingBuilder LoadingBuilder? null Custom widget shown while onSearch or onLoadMore is pending

Layout Modes

Single Select

The default mode for selecting a single item. It displays the label of the selected option in the trigger.

WSelect(
  value: 'apple',
  options: [
    SelectOption(value: 'apple', label: 'Apple'),
    SelectOption(value: 'banana', label: 'Banana'),
  ],
  onChange: (v) => print(v),
)

Multi Select

Enable isMulti: true to allow multiple selections. By default, it displays selected items as chips.

WSelect(
  isMulti: true,
  values: ['red', 'blue'],
  options: [
    SelectOption(value: 'red', label: 'Red'),
    SelectOption(value: 'blue', label: 'Blue'),
    SelectOption(value: 'green', label: 'Green'),
  ],
  onMultiChange: (list) => print(list),
)

Event Handling

WSelect provides callbacks for selection changes and remote interactions.

WSelect(
  onChange: (value) {
    // Handle single selection
  },
  onSearch: (query) async {
    // Return list of options based on search query
    return fetchRemoteOptions(query);
  },
  onLoadMore: () async {
    // Load next page of options
    return fetchNextPage();
  },
)

State Variants

WSelect automatically manages several states that you can style using prefixes in className:

  • hover: - When the mouse is over the trigger.
  • focus: - When the dropdown is open.
  • disabled: - When the widget is disabled.
  • selected: - When a value is selected.
WSelect(
  className: 'border-gray-300 hover:border-blue-500 focus:ring-2 focus:ring-blue-200',
)

Styling Examples

Searchable Select

Combine searchable: true with custom menu styling for a robust selection experience.

WSelect(
  searchable: true,
  searchPlaceholder: 'Search countries...',
  menuClassName: 'bg-white shadow-xl rounded-xl border border-gray-100',
  options: countries,
  onChange: (val) => _country = val,
)

Tagging (Create Option)

Allow users to create new options if a search yields no results.

WSelect(
  searchable: true,
  onCreateOption: (query) async {
    final newOpt = SelectOption(value: query.toLowerCase(), label: query);
    // Add to your local state/database
    return newOpt;
  },
  options: existingTags,
)

All Supported Classes

Category Classes
Layout flex, hidden, w-{size}, h-{size}
Spacing p-{n}, m-{n}, gap-{n}
Visuals bg-{color}, border, rounded, shadow
States hover:, focus:, disabled:, dark:
Custom open:, selected:

Customizing Theme

The default styling for WSelect and its chips can be influenced by the WindThemeData.

WindThemeData(
  colors: {
    'primary': Colors.indigo,
  },
)
  • WFormSelect - Form-integrated version with validation
  • WPopover - The underlying overlay engine
  • WInput - Used for the internal search field