Quick Start
This walks you through composing four CDX UI primitives into a working screen. Assumes you have completed Installation.
We will build:
- A theme installed via
createCdxTheme - An
AsyncViewrendering loading / empty / error / data states - A
SectionCardhosting the result list - A
ConfirmationDialog.destructivefor a row action
1. A sample model and loader
dart
class Area {
const Area({required this.id, required this.name, required this.capacity});
final String id;
final String name;
final int capacity;
}
Future<List<Area>> loadAreas() async {
await Future<void>.delayed(const Duration(milliseconds: 500));
return const [
Area(id: 'a1', name: 'Packing Line 1', capacity: 12),
Area(id: 'a2', name: 'Cold Storage', capacity: 40),
Area(id: 'a3', name: 'Inspection Bay', capacity: 8),
];
}2. Install the theme
createCdxTheme returns a ThemeData wired with every CDX component theme and registers a CdxConfig extension for tokens like controlHeight, containerPadding, gap tokens, icon sizing, status colors, and hover/selected tint.
dart
import 'package:flutter/material.dart';
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
import 'package:vyuh_cdx_ui/vyuh_cdx_ui.dart';
import 'package:vyuh_cdx_ui/cards.dart' show SectionCard;
final lightTheme = createCdxTheme(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
textTheme: ThemeData.light().textTheme,
);
class App extends StatelessWidget {
const App({super.key});
@override
Widget build(BuildContext context) => MaterialApp(
theme: lightTheme,
home: const AreasScreen(),
);
}3. Render with AsyncView
AsyncView<T> accepts a future, stream, or direct data. Builders for loading / empty / error states default to LoadingState, EmptyState, and ErrorState.
dart
class AreasScreen extends StatelessWidget {
const AreasScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Areas')),
body: AsyncView<List<Area>>(
future: loadAreas(),
contentBuilder: (context, areas) => _AreasList(areas: areas),
),
);
}
}Why not a plain FutureBuilder?
AsyncView ships the four canonical state widgets so every CDX screen gets the same centered layout, typography, and empty-collection heuristics — no ad-hoc CircularProgressIndicator() calls.
4. Group the list inside a SectionCard
dart
class _AreasList extends StatelessWidget {
const _AreasList({required this.areas});
final List<Area> areas;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16),
child: SectionCard(
icon: FluentIcons.building_factory_24_regular,
title: 'Active Areas',
child: Column(
children: [
for (final area in areas)
CompactCard(
title: area.name,
subtitle: 'Capacity: ${area.capacity}',
trailing: Button.icon(
icon: FluentIcons.delete_24_regular,
destructive: true,
tooltip: 'Delete area',
onPressed: () => _confirmDelete(context, area),
),
),
],
),
),
);
}
Future<void> _confirmDelete(BuildContext context, Area area) async {
await showDialog<void>(
context: context,
builder: (_) => ConfirmationDialog.destructive(
title: 'Delete ${area.name}?',
description: 'This action cannot be undone.',
confirmLabel: 'Delete',
onCancel: () => Navigator.of(context).pop(),
onConfirm: () {
// perform delete
Navigator.of(context).pop();
},
),
);
}
}What you just built
- A themed screen sharing
CdxConfigtokens with every other CDX widget - Four-state async rendering through one declarative widget
- A grouped list inside a
SectionCardusingCompactCardrows - A destructive confirmation dialog wired into a
Button.icon
Next steps
- Component Catalog — every export grouped by family
- Theming —
CdxConfigtokens, status palette, customization - Overlays — how dropdowns, menus, and pickers share one positioning + interaction layer