A comprehensive iOS-native design system for Flutter applications that follows Apple's Human Interface Guidelines. Build beautiful, consistent iOS apps with 35+ pre-built widgets, automatic dark mode support, and complete theming.
- 8 Color Palettes: System colors, labels, fills, backgrounds, separators, materials, and app-specific themes
- 22 Typography Styles: SF Pro Text font with all iOS text scales
- Automatic Dark Mode: Seamless light/dark theme switching
- App Themes: Pre-built themes for Music, Stocks, Weather, App Store, Books, and Podcast apps
- Layout: Scaffold, Navigation Bar, Toolbar, Grouped Tables, Rows
- Forms: Text Fields, Search Fields, Switches, Pickers, Date Pickers
- Buttons: Multiple sizes (Small, Medium, Large) and colors (Blue, Grey, Transparent)
- Display: Icons, Tags, Titles, Descriptions, Dividers, Markdown
- Modals: Bottom Sheets, Action Sheets, Search Modals, Apple Pay Sheets
- Specialized: Music Player, App Store, and custom app widgets
- Built-in
flutter_hookssupport for cleaner state management - No more
StatefulWidgetboilerplate - Automatic controller disposal
- Example patterns for all widgets
- Correct spacing (8pt grid system)
- Proper touch targets (44pt minimum)
- iOS animations and transitions
- Native iOS look and feel
Add to your pubspec.yaml:
dependencies:
ios_design_system:
git:
url: https://github.com/sampaio-tech/iOS-design-system.git
# Or use path for local development:
# path: ../ios_design_systemThen run:
flutter pub getimport 'package:flutter/cupertino.dart';
import 'package:ios_design_system/ios_design_system.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
final themeData = IosDarkThemeData(); // or IosLightThemeData()
return IosAnimatedTheme(
data: themeData,
child: CupertinoApp(
title: 'My iOS App',
theme: CupertinoThemeData(
brightness: themeData.brightness,
),
home: const HomeScreen(),
),
);
}
}import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:ios_design_system/ios_design_system.dart';
class SettingsScreen extends HookWidget {
const SettingsScreen({super.key});
@override
Widget build(BuildContext context) {
final notifications = useState(true);
final darkMode = useState(false);
return ScaffoldWidget(
navigationBar: CupertinoNavigatorBarWidget(
title: 'Settings',
imageFilter: NavigatorBarImageFilter.enabled,
leading: null,
trailing: null,
),
toolBar: null,
child: CupertinoScrollbar(
child: SingleChildScrollView(
child: SafeArea(
child: Column(
children: [
const SizedBox(height: 24),
GroupedTableWidget.rounded(
title: const TitleWidget(
text: 'PREFERENCES',
size: TitleSize.small,
),
rows: [
RowWidget.standard(
title: 'Notifications',
description: null,
leftWidget: null,
rightWidget: SwitchWidget(
value: notifications.value,
onChanged: (value) => notifications.value = value,
),
displayDivider: true,
onPressed: null,
onLongPress: null,
decorationCallback: null,
),
RowWidget.standard(
title: 'Dark Mode',
description: null,
leftWidget: null,
rightWidget: SwitchWidget(
value: darkMode.value,
onChanged: (value) => darkMode.value = value,
),
displayDivider: false,
onPressed: null,
onLongPress: null,
decorationCallback: null,
),
],
description: const DescriptionWidget(
text: 'Changes take effect immediately.',
),
),
],
),
),
),
),
);
}
}class ProfileForm extends HookWidget {
const ProfileForm({super.key});
@override
Widget build(BuildContext context) {
final nameController = useTextEditingController();
final emailController = useTextEditingController();
final isValid = useState(false);
// Auto-validation
useEffect(() {
void validate() {
isValid.value = nameController.text.isNotEmpty &&
emailController.text.contains('@');
}
nameController.addListener(validate);
emailController.addListener(validate);
return () {
nameController.removeListener(validate);
emailController.removeListener(validate);
};
}, [nameController, emailController]);
return Column(
children: [
GroupedTableWidget.rounded(
title: const TitleWidget(text: 'PROFILE', size: TitleSize.small),
rows: [
CupertinoTextFieldWidget(
placeholder: 'Name',
controller: nameController,
),
const DividerWidget(),
CupertinoTextFieldWidget(
placeholder: 'Email',
controller: emailController,
keyboardType: TextInputType.emailAddress,
),
],
description: null,
),
const SizedBox(height: 16),
ButtonWidget.label(
size: const LargeButtonSize(),
color: const BlueButtonColor(),
label: 'Save',
onPressed: isValid.value ? () {} : null,
),
],
);
}
}- ScaffoldWidget - Main screen container
- CupertinoNavigatorBarWidget - Navigation bar with blur
- ToolBarWidget - Bottom toolbar
- GroupedTableWidget - Settings-style lists
- RowWidget - Individual list rows
- CupertinoTextFieldWidget - Text input
- CupertinoSearchTextFieldWidget - Search field
- SwitchWidget - Toggle switch
- PickerButtonWidget - Date/time picker button
- CupertinoDatePickerWidget - Date/time picker
- CupertinoPickerWidget - Custom picker
- ButtonWidget - High-level themed button
- CupertinoButtonWidget - Base interactive widget
- Sizes: Small (28pt), Medium (34pt), Large (50pt)
- Colors: Blue, Grey Transparent, Blue Transparent, Custom
- IconWidget - Icons with backgrounds
- TagWidget - Selection tags/chips
- TitleWidget - Section headers
- DescriptionWidget - Help text
- DividerWidget - Separators
- MarkdownWidget - Markdown rendering
- CupertinoSheetWidget - Bottom sheets
- ModalSheetWidget - Search modals
- TitleSheetWidget - Sheet headers
- Supports drag-to-dismiss, nested navigation, Apple Pay variants
Access theme colors and typography:
@override
Widget build(BuildContext context) {
final theme = IosTheme.of(context);
// Colors
final primaryColor = theme.defaultColors.systemBlue;
final textColor = theme.defaultLabelColors.primary;
final backgroundColor = switch (theme) {
IosLightThemeData() => theme.defaultSystemBackgroundsColors.primaryLight,
IosDarkThemeData() => theme.defaultSystemBackgroundsColors.primaryDarkBase,
};
// Typography
final titleStyle = theme.typography.title1Bold;
final bodyStyle = theme.typography.bodyRegular;
return Container(
color: backgroundColor,
child: Text(
'Hello',
style: titleStyle.copyWith(color: textColor),
),
);
}Available Color Systems:
- System Colors -
systemBlue,systemRed,systemGreen, etc. - Label Colors -
primary,secondary,tertiary,quaternary - Fill Colors - Background fills for UI elements
- System Backgrounds - Screen-level backgrounds
- Grouped Backgrounds - Settings-style backgrounds
- Separator Colors - Dividers and borders
- System Materials - Blur effect colors
- App Decorations - Weather, Stocks, Music, App Store, Books, Podcast
This package includes flutter_hooks for cleaner state management:
// Traditional StatefulWidget (verbose)
class MyWidget extends StatefulWidget {
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late TextEditingController _controller;
@override
void initState() {
super.initState();
_controller = TextEditingController();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return TextField(controller: _controller);
}
}
// With Hooks (clean)
class MyWidget extends HookWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
final controller = useTextEditingController(); // Auto-disposed!
return TextField(controller: controller);
}
}Common Hooks:
useState- Simple stateuseTextEditingController- Text field controlleruseEffect- Side effects and listenersuseMemoized- Cache expensive operationsuseAnimationController- Animations
Pre-built themes for common iOS app styles:
NeutralCardWidget(
child: Column(
children: [
// Album art
NeutralCircularButtonWidget(
iconData: CupertinoIcons.play_fill,
onPressed: () {},
),
NeutralPillButtonWidget(
label: 'Add to Playlist',
leftIcon: CupertinoIcons.add,
onPressed: () {},
),
],
),
)GroupedTableWidget.stocks(
title: const TitleWidget(text: 'WATCHLIST', size: TitleSize.small),
rows: [
RowWidget.stocks(
title: 'AAPL',
description: 'Apple Inc.',
rightWidget: Text('+2.5%'),
onPressed: () {},
),
],
)AppIconWidget(
imageUrl: 'https://example.com/icon.png',
size: 60,
borderRadius: 12,
)Follow the design system patterns to create your own widgets:
import 'package:flutter/cupertino.dart';
import 'package:ios_design_system/ios_design_system.dart';
class MyCustomWidget extends StatelessWidget {
const MyCustomWidget({
required this.title,
this.subtitle,
super.key,
});
final String title;
final String? subtitle;
@override
Widget build(BuildContext context) {
final theme = IosTheme.of(context);
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: switch (theme) {
IosLightThemeData() =>
theme.defaultSystemBackgroundsColors.primaryLight,
IosDarkThemeData() =>
theme.defaultSystemBackgroundsColors.primaryDarkElevated,
},
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: theme.typography.bodyBold.copyWith(
color: theme.defaultLabelColors.primary,
),
),
if (subtitle != null) ...[
const SizedBox(height: 4),
Text(
subtitle!,
style: theme.typography.caption1Regular.copyWith(
color: theme.defaultLabelColors.secondary,
),
),
],
],
),
);
}
}Comprehensive rules in .cursor/rules/:
00-project-overview.md- Project structure and principles01-theme-system.md- Complete theme documentation02-button-system.md- Button system guide03-layout-widgets.md- Layout components04-form-widgets.md- Form widgets05-display-widgets.md- Display components06-sheet-modals.md- Sheets and modals07-specialized-widgets.md- App-specific widgets08-apple-hig-guidelines.md- iOS design standards09-code-patterns.md- Common patterns and recipes10-file-organization.md- File structure and conventions11-flutter-hooks-patterns.md- Hook patterns
Task-specific skills in .claude/skills/:
theme-system/- Theme colors and typographybutton-system/- Button componentslayout-widgets/- Layout componentsform-widgets/- Form inputsdisplay-widgets/- Display componentssheet-modals/- Modal presentationsapp-themes/- App-specific themesflutter-hooks/- Hook patternscreate-widget/- Widget creation guide
- Always use theme colors - Never hardcode colors
- Follow Apple HIG - Correct spacing, sizing, and behavior
- Support dark mode - Test in both themes
- Use hooks - Cleaner state management
- Type safety - Sealed classes for variants
- Composability - Build complex UIs from simple widgets
cd example
flutter pub get
flutter runThe example app demonstrates:
- Theme switching
- All widget categories
- Form validation
- Modal presentations
- Navigation patterns
- Flutter hooks usage
- Flutter SDK (>=3.7.0 <4.0.0)
- Dart SDK (>=3.0.0)
MCP enables AI assistants to interact with your Flutter project:
-
Copy the example configuration:
cp .cursor/mcp.json.example .cursor/mcp.json
-
Update Dart SDK path in
.cursor/mcp.json:which flutter # Use: <flutter_path>/bin/cache/dart-sdk/bin/dart -
Restart Cursor IDE
Ralph Orchestrator is an AI-powered coding tool:
-
Install Ralph:
npm install -g ralph-orchestrator
-
Initialize and configure:
ralph init --backend claude cp ralph.yml.example ralph.yml
-
Update
ralph.ymlwith your git settings -
Run Ralph:
ralph run
We welcome contributions! To maintain consistency:
- Follow Apple HIG - Match iOS native appearance
- Use theme exclusively - No hardcoded colors or styles
- Support both themes - Test light and dark modes
- Include examples - Update example app
- Add documentation - Update relevant skill/rule files
- Write tests - Include unit tests for new widgets
- Create widget file:
/lib/src/widgets/my_widget.dart - Export in
/lib/src/widgets/exports.dart - Add tests in
/test/widgets/my_widget_test.dart - Update example app
- Document in
.claude/skills/and.cursor/rules/
See Complete Widget Creation Guide β
# Run all tests
flutter test
# Run specific test
flutter test test/widgets/button_widget_test.dart
# Run with coverage
flutter test --coveragedependencies:
flutter:
sdk: flutter
flutter_svg: ^2.0.17 # SVG support
gpt_markdown: 1.0.19 # Markdown rendering
flutter_math_fork: 0.7.4 # LaTeX math
flutter_hooks: ^0.21.2 # Hook-based state
intl: ^0.20.0 # Date formatting- Additional app themes (Notes, Reminders, Calendar)
- More specialized widgets
- Accessibility improvements
- Performance optimizations
- Web platform support
- Additional examples
This project is licensed under the MIT License - see the LICENSE file for details.
- Apple Inc. for the Human Interface Guidelines
- Flutter team for the amazing framework
- flutter_hooks for cleaner state management
- All contributors to this project
- Apple Human Interface Guidelines
- Flutter Documentation
- flutter_hooks Documentation
- Example App
- Full Documentation
Made with β€οΈ for iOS developers using Flutter