dropx 0.0.2
dropx: ^0.0.2 copied to clipboard
A highly customizable, theme-aware dropdown widget for Flutter with full keyboard navigation, search functionality, and auto-positioning.
DropX #
A fully customizable dropdown package for Flutter with keyboard navigation support.
Screenshots #
![]() |
![]() |
![]() |
| Basic Dropdown | Search & Filter | Clear Button |
![]() |
![]() |
|
| Custom Styling | Form Validation |
π‘ Try it yourself! Run the example app to see all features in action:
cd example && flutter run
Features #
- β¨ Full keyboard navigation - Arrow keys, Enter, Escape
- π Built-in search and filtering - With custom filter support and debouncing
- π Smart auto-positioning - Shows above/below based on available space
- π¨ Fully customizable styling - Every color and dimension configurable
- π Theme-aware - Automatically adapts to your app's theme
- β‘ Loading states - Built-in loading indicator support
- π― Custom item builders - Complete control over item rendering
- π± Responsive - Works on all screen sizes
- βΏ Accessible - Semantic labels and focus management
- π±οΈ Click outside to close - Dropdown closes when clicking outside
- π Dynamic updates - Items automatically update when data changes
- β Clear button - Optional clear button to reset selection
- π Form validation - Built-in FormField wrapper for easy form integration
- β±οΈ Search debouncing - Optimize performance for large lists
Installation #
dependencies:
dropx: ^0.0.2
Usage #
import 'package:dropx/dropx.dart';
Dropx<String>(
items: ['Apple', 'Banana', 'Cherry'],
focusNode: FocusNode(),
hint: 'Select a fruit',
onSelected: (value) => print(value),
)
Custom styling #
Dropx<String>(
items: items,
focusNode: focusNode,
hint: 'Select',
onSelected: (value) => print(value),
config: DropxConfig(
maxHeight: 400,
borderRadius: BorderRadius.circular(16),
showItemDividers: true,
style: DropxStyle(
overlayBackgroundColor: Colors.blue.shade50,
selectedItemBackgroundColor: Colors.blue.shade200,
),
),
)
Custom items #
Dropx<User>(
items: users,
focusNode: focusNode,
hint: 'Select user',
displayText: (user) => user.name,
itemBuilder: (user, isSelected) {
return ListTile(
leading: CircleAvatar(child: Text(user.initials)),
title: Text(user.name),
subtitle: Text(user.email),
);
},
onSelected: (user) => print(user.name),
)
Custom filter #
Dropx<Product>(
items: products,
focusNode: focusNode,
displayText: (product) => product.name,
customFilter: (product, query) {
return product.name.contains(query) || product.sku.contains(query);
},
onSelected: (product) => print(product.name),
)
Clear button #
Dropx<String>(
items: items,
focusNode: focusNode,
hint: 'Select',
onSelected: (value) => print(value),
showClearButton: true,
onClear: () => print('Selection cleared'),
)
Form validation #
Form(
key: formKey,
child: DropxFormField<String>(
items: ['Option 1', 'Option 2', 'Option 3'],
hint: 'Select an option',
validator: (value) {
if (value == null) return 'Please select an option';
return null;
},
onSaved: (value) => print('Saved: $value'),
),
)
Search debouncing #
Dropx<String>(
items: largeItemList,
focusNode: focusNode,
hint: 'Search...',
onSelected: (value) => print(value),
config: DropxConfig(
searchDebounce: Duration(milliseconds: 300),
),
)
Async loading #
class MyWidget extends StatefulWidget {
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
List<String> items = [];
bool isLoading = true;
@override
void initState() {
super.initState();
_loadItems();
}
Future<void> _loadItems() async {
// Simulate API call
await Future.delayed(Duration(seconds: 2));
setState(() {
items = ['Item 1', 'Item 2', 'Item 3'];
isLoading = false;
});
}
@override
Widget build(BuildContext context) {
return Dropx<String>(
items: items,
focusNode: FocusNode(),
hint: 'Select item',
onSelected: (value) => print(value),
isLoading: isLoading,
);
}
}
API Reference #
Dropx Parameters #
| Parameter | Type | Description | Default |
|---|---|---|---|
items |
List<T> |
List of items to display | Required |
focusNode |
FocusNode |
Focus node for keyboard navigation | Required |
onSelected |
Function(T) |
Callback when item is selected | Required |
hint |
String? |
Placeholder text | null |
initialValue |
T? |
Initial selected value | null |
displayText |
String Function(T)? |
Custom text extractor | toString() |
itemBuilder |
Widget Function(T, bool)? |
Custom item widget builder | null |
customFilter |
bool Function(T, String)? |
Custom filter function | null |
config |
DropxConfig? |
Configuration options | DropxConfig() |
header |
Widget? |
Widget shown at top of dropdown | null |
footer |
Widget? |
Widget shown at bottom of dropdown | null |
emptyWidget |
Widget? |
Widget shown when no items | Default message |
isLoading |
bool |
Show loading indicator | false |
enabled |
bool |
Enable/disable dropdown | true |
enableSearch |
bool |
Enable search functionality | true |
showClearButton |
bool |
Show clear button when value selected | false |
onClear |
VoidCallback? |
Callback when clear button pressed | null |
onChanged |
ValueChanged<String>? |
Callback when text changes | null |
semanticLabel |
String? |
Accessibility label | null |
DropxConfig Options #
See ARCHITECTURE.md for complete configuration options.
Performance Tips #
- Use
constconstructors where possible - Provide
displayTextfor complex objects to avoid repeatedtoString()calls - Use
customFilterfor optimized filtering logic - Consider pagination for very large lists (>1000 items)
Accessibility #
DropX includes built-in accessibility features:
- Semantic labels for screen readers
- Keyboard navigation support
- Focus management
- High contrast support through theme integration
More #
See ARCHITECTURE.md for package details and example/ for more examples.
Contributing #
Contributions are welcome! Please read CONTRIBUTING.md for details.
License #
MIT License - see LICENSE file.




