Next UI

Beautiful, modern and fast Flutter UI library inspired by HeroUI design
principles.
Features โจ
- ๐จ Modern Design: Components following HeroUI design principles
- ๐ High Performance: Optimized for Flutter's rendering engine
- ๐ฑ Responsive: Works seamlessly across different screen sizes
- ๐ฏ Type Safe: Built with strong typing and comprehensive enums
- ๐งฉ Composable: Easy to combine and customize components
- โฟ Accessible: Built with accessibility in mind
- ๐ Well Documented: Comprehensive documentation and examples
Installation ๐ป
โ In order to start using Next UI you must have the
Flutter SDK installed on your machine.
Install via flutter pub add:
flutter pub add next_ui
Quick Start ๐
import 'package:flutter/material.dart';
import 'package:next_ui/next_ui.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Button Examples
Button.solid(
child: Text('Primary Button'),
onPressed: () {},
),
SizedBox(height: 16),
// Switch Example
NextSwitch(
isSelected: true,
label: Text('Enable Feature'),
onValueChange: (value) {},
// Input Example
NextInput(
label: 'Email',
placeholder: 'Enter your email',
startContent: Icon(Icons.email),
// Switch Example
NextSwitch(
isSelected: true,
label: Text('Enable Feature'),
onValueChange: (value) {},
),
SizedBox(height: 16),
// Input Example
NextInput(
label: 'Email',
placeholder: 'Enter your email',
startContent: Icon(Icons.email),
),
SizedBox(height: 16),
// Chip Example
NextChip.solid(
child: Text('Success'),
color: ChipColor.success,
),
SizedBox(height: 16),
// Card Example
NextCard(
header: Text('Welcome'),
body: Text('This is a beautiful card component.'),
footer: ElevatedButton(
onPressed: () {},
child: Text('Action'),
),
),
SizedBox(height: 16),
// Progress Example
NextCircularProgress(
value: 0.7,
isIndeterminate: false,
label: Text('70% Complete'),
),
],
),
),
),
);
}
}
Components Overview ๐ฆ
โ
Completed Components
| Component |
Features |
Status |
| Button |
7 variants, 3 sizes, 6 colors, loading states, icons |
โ
Complete |
| Card |
Header/body/footer structure, shadows, radius, interactive |
โ
Complete |
| Chip |
7 variants, 3 sizes, 6 colors, closable, avatar support |
โ
Complete |
| Switch |
3 sizes, 6 colors, label support, icons, disabled states |
โ
Complete |
| Input |
4 variants, 3 sizes, 6 colors, validation, OTP support |
โ
Complete |
| Switch |
3 sizes, 6 colors, label support, icons, disabled states |
โ
Complete |
| Checkbox |
3 sizes, 6 colors, indeterminate state, validation |
โ
Complete |
| Checkbox Group |
Multi-selection, validation, orientation control |
โ
Complete |
| Radio Group |
Single selection, validation, horizontal/vertical layout |
โ
Complete |
| Circular Progress |
Determinate/indeterminate, custom labels, stroke width |
โ
Complete |
| Typography |
H1-H6, paragraph, caption, multiple weights |
โ
Complete |
๐ง Roadmap
| Planned Components |
Status |
| Button Group |
๐ Planned |
| Input/TextField |
๐ Planned |
| Switch |
๐ Planned |
| Input/TextField |
๐ Planned |
| Switch |
๐ Planned |
| Avatar |
๐ Planned |
| Badge |
๐ Planned |
| Modal |
๐ Planned |
| Dropdown |
๐ Planned |
| Table |
๐ Planned |
| Tooltip |
๐ Planned |
| Navbar |
๐ Planned |
| Pagination |
๐ Planned |
| Dark Mode Support |
๐ Planned |
Component Examples ๐
// Variants
Button.solid(child: Text('Solid'), onPressed: () {});
Button.bordered(child: Text('Bordered'), onPressed: () {});
Button.light(child: Text('Light'), onPressed: () {});
Button.ghost(child: Text('Ghost'), onPressed: () {});
// Colors
Button.solid(
color: ButtonColor.primary,
child: Text('Primary'),
onPressed: () {},
);
// Sizes
Button.solid(
size: ButtonSize.lg,
child: Text('Large'),
onPressed: () {},
);
// Loading State
Button.solid(
isLoading: true,
child: Text('Loading...'),
onPressed: () {},
);
// With Icons
Button.solid(
startContent: Icon(Icons.download),
child: Text('Download'),
onPressed: () {},
);
Card
// Basic Card
NextCard(
header: Text('Card Title', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
body: Text('This is the card body content.'),
footer: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(onPressed: () {}, child: Text('Cancel')),
SizedBox(width: 8),
ElevatedButton(onPressed: () {}, child: Text('Save')),
],
),
);
// Pressable Card
NextCard(
isPressable: true,
onPressed: () => print('Card pressed'),
body: Column(
children: [
Icon(Icons.favorite, size: 48, color: Colors.red),
SizedBox(height: 8),
Text('Tap this card'),
],
),
);
// Different Shadows and Radius
NextCard(
shadow: CardShadow.lg,
radius: CardRadius.md,
body: Text('Large shadow, medium radius'),
);
// Blurred Footer
NextCard(
header: Text('Settings'),
body: Text('Configure your preferences here.'),
footer: Text('Footer with blur effect'),
isFooterBlurred: true,
);
// Using CardHeader, CardBody, CardFooter directly
NextCard(
children: [
CardHeader(
padding: EdgeInsets.all(20),
child: Text('Custom Header'),
),
CardBody(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 16),
child: Text('Custom body content with custom padding.'),
),
CardFooter(
child: Icon(Icons.star, color: Colors.amber),
),
],
);
Chip
// Basic Chip
NextChip.solid(child: Text('Solid Chip'));
// With Avatar
NextChip.solid(
avatar: CircleAvatar(child: Text('A')),
child: Text('Avatar Chip'),
);
// Closable
NextChip.solid(
child: Text('Closable'),
onClose: (event) => print('Chip closed'),
);
// Dot Variant
NextChip.dot(
color: ChipColor.success,
child: Text('Status'),
);
Switch
// Basic Switch
NextSwitch(
isSelected: true,
onValueChange: (value) => print('Switch: $value'),
);
// Switch with Label
NextSwitch(
isSelected: false,
label: Text('Enable notifications'),
onValueChange: (value) {},
);
// Switch Sizes
NextSwitch.small(isSelected: true); // Small
NextSwitch.medium(isSelected: true); // Medium (default)
NextSwitch.large(isSelected: true); // Large
// Switch Colors
NextSwitch(
color: SwitchColor.primary,
isSelected: true,
onValueChange: (value) {},
);
// Switch with Icons
NextSwitch(
isSelected: true,
label: Text('Dark Mode'),
startContent: Icon(Icons.dark_mode),
thumbIcon: Icon(Icons.check, size: 16, color: Colors.white),
onValueChange: (value) {},
);
// Disabled Switch
NextSwitch(
isSelected: true,
isDisabled: true,
label: Text('Disabled'),
);
// Read-only Switch
NextSwitch(
isSelected: true,
isReadOnly: true,
label: Text('Read-only'),
);
// Controlled Switch
bool isEnabled = false;
NextSwitch(
isSelected: isEnabled,
label: Text('Toggle Feature'),
onValueChange: (value) {
setState(() {
isEnabled = value;
});
},
### Input
```dart
// Basic Input
NextInput(
label: 'Username',
placeholder: 'Enter your username',
);
// Input Variants
NextInput(variant: InputVariant.flat); // Default
NextInput(variant: InputVariant.bordered); // With border
NextInput(variant: InputVariant.faded); // Faded background
NextInput(variant: InputVariant.underlined);// Underlined
// Colors and Sizes
NextInput(
color: InputColor.primary,
size: InputSize.lg,
label: 'Large Primary Input',
);
// Password Input
NextInput(
label: 'Password',
obscureText: true,
startContent: Icon(Icons.lock),
);
// Input with Validation
NextInput(
label: 'Email',
isRequired: true,
isInvalid: emailError,
errorMessage: 'Please enter a valid email',
keyboardType: TextInputType.emailAddress,
);
// Clearable Input
NextInput(
label: 'Search',
isClearable: true,
startContent: Icon(Icons.search),
);
// Textarea
NextInput(
label: 'Message',
maxLines: 4,
description: 'Tell us what you think',
);
// Label Placements
NextInput(
labelPlacement: LabelPlacement.outside,
label: 'Outside Label',
);
// Basic 6-digit OTP
NextInputOTP(
length: 6,
onCompleted: (value) => print('OTP: $value'),
);
// Custom 4-digit OTP
NextInputOTP(
length: 4,
size: InputSize.lg,
color: InputColor.success,
spacing: 12,
);
// OTP with Separator
NextInputOTP(
length: 6,
separator: Text('-', style: TextStyle(fontSize: 24)),
);
// Secure OTP
NextInputOTP(
length: 4,
obscureText: true,
keyboardType: TextInputType.number,
### Switch
```dart
// Basic Switch
NextSwitch(
isSelected: true,
onValueChange: (value) => print('Switch: $value'),
);
// Switch with Label
NextSwitch(
isSelected: false,
label: Text('Enable notifications'),
onValueChange: (value) {},
);
// Switch Sizes
NextSwitch.small(isSelected: true); // Small
NextSwitch.medium(isSelected: true); // Medium (default)
NextSwitch.large(isSelected: true); // Large
// Switch Colors
NextSwitch(
color: SwitchColor.primary,
isSelected: true,
onValueChange: (value) {},
);
// Switch with Icons
NextSwitch(
isSelected: true,
label: Text('Dark Mode'),
startContent: Icon(Icons.dark_mode),
thumbIcon: Icon(Icons.check, size: 16, color: Colors.white),
onValueChange: (value) {},
);
// Disabled Switch
NextSwitch(
isSelected: true,
isDisabled: true,
label: Text('Disabled'),
);
// Read-only Switch
NextSwitch(
isSelected: true,
isReadOnly: true,
label: Text('Read-only'),
);
// Controlled Switch
bool isEnabled = false;
NextSwitch(
isSelected: isEnabled,
label: Text('Toggle Feature'),
onValueChange: (value) {
setState(() {
isEnabled = value;
});
},
### Input
```dart
// Basic Input
NextInput(
label: 'Username',
placeholder: 'Enter your username',
);
// Input Variants
NextInput(variant: InputVariant.flat); // Default
NextInput(variant: InputVariant.bordered); // With border
NextInput(variant: InputVariant.faded); // Faded background
NextInput(variant: InputVariant.underlined);// Underlined
// Colors and Sizes
NextInput(
color: InputColor.primary,
size: InputSize.lg,
label: 'Large Primary Input',
);
// Password Input
NextInput(
label: 'Password',
obscureText: true,
startContent: Icon(Icons.lock),
);
// Input with Validation
NextInput(
label: 'Email',
isRequired: true,
isInvalid: emailError,
errorMessage: 'Please enter a valid email',
keyboardType: TextInputType.emailAddress,
);
// Clearable Input
NextInput(
label: 'Search',
isClearable: true,
startContent: Icon(Icons.search),
);
// Textarea
NextInput(
label: 'Message',
maxLines: 4,
description: 'Tell us what you think',
);
// Label Placements
NextInput(
labelPlacement: LabelPlacement.outside,
label: 'Outside Label',
);
// Basic 6-digit OTP
NextInputOTP(
length: 6,
onCompleted: (value) => print('OTP: $value'),
);
// Custom 4-digit OTP
NextInputOTP(
length: 4,
size: InputSize.lg,
color: InputColor.success,
spacing: 12,
);
// OTP with Separator
NextInputOTP(
length: 6,
separator: Text('-', style: TextStyle(fontSize: 24)),
);
// Secure OTP
NextInputOTP(
length: 4,
obscureText: true,
keyboardType: TextInputType.number,
);
Checkbox
// Basic Checkbox
NextCheckbox(
children: Text('Accept terms'),
onValueChange: (value) => print('Value: $value'),
);
// Indeterminate
NextCheckbox(
children: Text('Select All'),
isIndeterminate: true,
);
// Checkbox Group
NextCheckboxGroup(
label: 'Select your interests',
children: [
NextGroupCheckbox(value: 'sports', children: Text('Sports')),
NextGroupCheckbox(value: 'music', children: Text('Music')),
NextGroupCheckbox(value: 'travel', children: Text('Travel')),
],
);
Radio Group
RadioGroup(
label: Text('Choose framework'),
children: [
NextRadio(value: 'flutter', child: Text('Flutter')),
NextRadio(value: 'react', child: Text('React Native')),
NextRadio(value: 'native', child: Text('Native')),
],
);
// Horizontal Layout
RadioGroup(
orientation: RadioGroupOrientation.horizontal,
children: [
NextRadio(value: 'yes', child: Text('Yes')),
NextRadio(value: 'no', child: Text('No')),
],
);
Circular Progress
// Indeterminate
NextCircularProgress(
label: Text('Loading...'),
);
// Determinate
NextCircularProgress(
value: 0.75,
isIndeterminate: false,
label: Text('Progress'),
showValueLabel: true,
);
// Custom Colors and Sizes
NextCircularProgress(
value: 0.8,
color: CircularProgressColor.success,
size: CircularProgressSize.lg,
strokeWidth: 4,
label: Text('Upload Complete'),
);
Example App ๐ฑ
The package includes a comprehensive example app showcasing all components:
cd example
flutter run
The example app features:
- 7 Interactive Tabs: Buttons,Cards, Chips, Switches, Inputs, Checkboxes, Radio
Groups, Progress, Typography
- Live Demonstrations: All variants, sizes, colors, and states
- Interactive Controls: Real-time component customization
- Best Practices: Proper usage patterns and code examples
Theme Customization ๐จ
Next UI components integrate with Flutter's Material Theme:
MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
textTheme: TextTheme(
headlineSmall: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
),
home: MyHomePage(),
);
Custom Colors
// Components support multiple color variants
Button.solid(color: ButtonColor.primary); // Blue
Button.solid(color: ButtonColor.success); // Green
Button.solid(color: ButtonColor.warning); // Orange
Button.solid(color: ButtonColor.danger); // Red
Button.solid(color: ButtonColor.secondary); // Purple
API Reference ๐
| Property |
Type |
Description |
child |
Widget? |
Button content |
onPressed |
VoidCallback? |
Tap callback |
variant |
ButtonVariant |
Visual style |
color |
ButtonColor |
Color theme |
size |
ButtonSize |
Button size |
isLoading |
bool |
Loading state |
isDisabled |
bool |
Disabled state |
startContent |
Widget? |
Leading icon |
endContent |
Widget? |
Trailing icon |
NextCard
| Property |
Type |
Description |
header |
Widget? |
Header content widget |
body |
Widget? |
Body content widget |
footer |
Widget? |
Footer content widget |
children |
List<Widget>? |
Alternative content children |
shadow |
CardShadow |
Shadow depth |
radius |
CardRadius |
Border radius |
fullWidth |
bool |
Take full width |
isHoverable |
bool |
Enable hover effects |
isPressable |
bool |
Make card pressable |
isBlurred |
bool |
Apply blur effect |
isFooterBlurred |
bool |
Blur footer only |
isDisabled |
bool |
Disable interactions |
disableAnimation |
bool |
Disable animations |
disableRipple |
bool |
Disable ripple effects |
allowTextSelectionOnPress |
bool |
Allow text selection on press |
onPressed |
VoidCallback? |
Press callback |
onPressStart |
VoidCallback? |
Press start callback |
onPressEnd |
VoidCallback? |
Press end callback |
onPressChange |
ValueChanged<bool>? |
Press state change callback |
onPressUp |
VoidCallback? |
Press up callback |
padding |
EdgeInsetsGeometry? |
Internal padding |
margin |
EdgeInsetsGeometry? |
External margin |
height |
double? |
Fixed height |
width |
double? |
Fixed width |
decoration |
BoxDecoration? |
Custom decoration |
constraints |
BoxConstraints? |
Size constraints |
NextChip
| Property |
Type |
Description |
child |
Widget? |
Chip content |
variant |
ChipVariant |
Visual style |
color |
ChipColor |
Color theme |
size |
ChipSize |
Chip size |
avatar |
Widget? |
Avatar widget |
onClose |
Function? |
Close callback |
startContent |
Widget? |
Leading content |
endContent |
Widget? |
Trailing content |
NextSwitch
| Property |
Type |
Description |
value |
String? |
Form field value |
isSelected |
bool? |
Whether switch is selected |
defaultSelected |
bool |
Default selected state |
onChanged |
ValueChanged<bool>? |
Native change callback |
onValueChange |
ValueChanged<bool>? |
Value change callback |
size |
SwitchSize |
Switch size (sm, md, lg) |
color |
SwitchColor |
Color theme |
label |
Widget? |
Label widget |
startContent |
Widget? |
Leading content widget |
endContent |
Widget? |
Trailing content widget |
thumbIcon |
Widget? |
Icon inside thumb |
isDisabled |
bool |
Disabled state |
isReadOnly |
bool |
Read-only state |
disableAnimation |
bool |
Disable animations |
name |
String? |
Form field name |
autofocus |
bool |
Auto-focus on mount |
focusNode |
FocusNode? |
Focus node |
margin |
EdgeInsetsGeometry? |
External margin |
padding |
EdgeInsetsGeometry? |
Internal padding |
| Property |
Type |
Description |
controller |
TextEditingController? |
Text editing controller |
value |
String? |
Initial text value |
onChanged |
ValueChanged<String>? |
Text change callback |
onSubmitted |
ValueChanged<String>? |
Submit callback |
onClear |
VoidCallback? |
Clear button callback |
variant |
InputVariant |
Visual style variant |
color |
InputColor |
Color theme |
size |
InputSize |
Input field size |
radius |
InputRadius |
Border radius |
labelPlacement |
LabelPlacement |
Label position |
label |
String? |
Label text |
placeholder |
String? |
Placeholder text |
description |
String? |
Helper description |
errorMessage |
String? |
Error message |
startContent |
Widget? |
Leading widget |
endContent |
Widget? |
Trailing widget |
isRequired |
bool |
Required field indicator |
isDisabled |
bool |
Disabled state |
isReadOnly |
bool |
Read-only state |
isInvalid |
bool |
Invalid state |
isClearable |
bool |
Show clear button |
obscureText |
bool |
Password mode |
maxLines |
int? |
Maximum lines |
keyboardType |
TextInputType? |
Keyboard type |
| Property |
Type |
Description |
length |
int |
Number of OTP digits |
onChanged |
ValueChanged<String>? |
Value change callback |
onCompleted |
ValueChanged<String>? |
Completion callback |
separator |
Widget? |
Custom separator widget |
size |
InputSize |
Input field size |
color |
InputColor |
Color theme |
spacing |
double |
Spacing between fields |
isDisabled |
bool |
Disabled state |
isInvalid |
bool |
Invalid state |
obscureText |
bool |
Hide input text |
keyboardType |
TextInputType |
Keyboard type |
NextSwitch
| Property |
Type |
Description |
value |
String? |
Form field value |
isSelected |
bool? |
Whether switch is selected |
defaultSelected |
bool |
Default selected state |
onChanged |
ValueChanged<bool>? |
Native change callback |
onValueChange |
ValueChanged<bool>? |
Value change callback |
size |
SwitchSize |
Switch size (sm, md, lg) |
color |
SwitchColor |
Color theme |
label |
Widget? |
Label widget |
startContent |
Widget? |
Leading content widget |
endContent |
Widget? |
Trailing content widget |
thumbIcon |
Widget? |
Icon inside thumb |
isDisabled |
bool |
Disabled state |
isReadOnly |
bool |
Read-only state |
disableAnimation |
bool |
Disable animations |
name |
String? |
Form field name |
autofocus |
bool |
Auto-focus on mount |
focusNode |
FocusNode? |
Focus node |
margin |
EdgeInsetsGeometry? |
External margin |
padding |
EdgeInsetsGeometry? |
Internal padding |
| Property |
Type |
Description |
controller |
TextEditingController? |
Text editing controller |
value |
String? |
Initial text value |
onChanged |
ValueChanged<String>? |
Text change callback |
onSubmitted |
ValueChanged<String>? |
Submit callback |
onClear |
VoidCallback? |
Clear button callback |
variant |
InputVariant |
Visual style variant |
color |
InputColor |
Color theme |
size |
InputSize |
Input field size |
radius |
InputRadius |
Border radius |
labelPlacement |
LabelPlacement |
Label position |
label |
String? |
Label text |
placeholder |
String? |
Placeholder text |
description |
String? |
Helper description |
errorMessage |
String? |
Error message |
startContent |
Widget? |
Leading widget |
endContent |
Widget? |
Trailing widget |
isRequired |
bool |
Required field indicator |
isDisabled |
bool |
Disabled state |
isReadOnly |
bool |
Read-only state |
isInvalid |
bool |
Invalid state |
isClearable |
bool |
Show clear button |
obscureText |
bool |
Password mode |
maxLines |
int? |
Maximum lines |
keyboardType |
TextInputType? |
Keyboard type |
| Property |
Type |
Description |
length |
int |
Number of OTP digits |
onChanged |
ValueChanged<String>? |
Value change callback |
onCompleted |
ValueChanged<String>? |
Completion callback |
separator |
Widget? |
Custom separator widget |
size |
InputSize |
Input field size |
color |
InputColor |
Color theme |
spacing |
double |
Spacing between fields |
isDisabled |
bool |
Disabled state |
isInvalid |
bool |
Invalid state |
obscureText |
bool |
Hide input text |
keyboardType |
TextInputType |
Keyboard type |
NextCheckbox
| Property |
Type |
Description |
children |
Widget? |
Label content |
isSelected |
bool? |
Selection state |
onValueChange |
ValueChanged<bool>? |
Change callback |
color |
CheckboxColor |
Color theme |
size |
CheckboxSize |
Checkbox size |
isIndeterminate |
bool |
Indeterminate state |
isDisabled |
bool |
Disabled state |
isInvalid |
bool |
Invalid state |
Contributing ๐ค
We welcome contributions! Please see our Contributing Guide
for details.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature)
- Commit your changes (
git commit -m 'Add amazing feature')
- Push to the branch (
git push origin feature/amazing-feature)
- Open a Pull Request
Testing ๐งช
For first time users, install the very_good_cli:
dart pub global activate very_good_cli
To run all unit tests:
very_good test --coverage
To view the generated coverage report you can use
lcov:
# Generate Coverage Report
genhtml coverage/lcov.info -o coverage/
# Open Coverage Report
open coverage/index.html
License ๐
This project is licensed under the MIT License - see the LICENSE file
for details.
Links & References ๐