Query Controls, Animation, Keys & Progress
A handful of small standalone widgets and helpers that don't warrant their own pages.
Live examples
Open the full Feedback and Progress example.
ChoiceChipGroup
Single-select chip strip used by query-driven view controls. The underlying class is ChoiceChipGroup<T>.
ChoiceChipGroup<TaskStatus>(
options: const [
ChipOption(value: TaskStatus.pending, label: 'Pending'),
ChipOption(value: TaskStatus.approved, label: 'Approved'),
ChipOption(value: TaskStatus.rejected, label: 'Rejected'),
],
selected: filter.status,
onSelected: (s) => filter.setStatus(s), // null when re-tapping the active chip
leadingIcon: FluentIcons.filter_24_regular,
semanticKey: const SemanticKey('inbox.filter.status'),
)Tapping the already-selected chip deselects it (passes null).
Beacon
Attention-grabbing pulse indicator. Two visual modes:
| Mode | Triggered by | Use |
|---|---|---|
| Ring | non-null icon | Timeline pending nodes — circle with icon, animated outer ring |
| Glow dot | icon == null | Status indicators — glowing dot with expanding ripple |
// Pending timeline indicator
Beacon(
icon: FluentIcons.hourglass_24_regular,
color: theme.colorScheme.primary,
size: 32,
iconSize: 16,
pulsing: true,
)
// Onboarding "look here" dot
Beacon(
color: Colors.red,
size: 8,
pulsing: true,
)
// Static (non-animated) variant — faint outer circle instead of pulse
Beacon(
icon: FluentIcons.warning_24_regular,
color: cdxColors.warning,
pulsing: false,
)SemanticKey
Structured widget identification for automation, testing, and analytics. Composes dot-separated hierarchical paths.
abstract final class InboxKeys {
static const dashboard = SemanticKey('inbox.dashboard');
}
// Compose
final searchKey = (InboxKeys.dashboard / 'field' / 'search').value;
// → ValueKey('inbox.dashboard.field.search')
TextField(key: searchKey, ...)Naming convention: screen.widgetType.name using camelCase within each segment and dots as separators (dots cannot appear in Dart identifiers, avoiding delimiter collisions).
Progress
Two themed progress indicators with sensible defaults.
CircularProgress
CircularProgress() // 24 px indeterminate
CircularProgress(size: 16, strokeWidth: 2) // small inline spinner
CircularProgress(value: 0.75) // determinate
CircularProgress(color: Colors.green, trackColor: Colors.green.shade100)Defaults: 24 px, stroke 3, color = colorScheme.primary, track = colorScheme.surfaceContainerHighest.
LineProgress
LineProgress() // indeterminate, 3 px tall pill
LineProgress(value: 0.6) // determinate
LineProgress(height: 4, borderRadius: 2) // square edges
LineProgress(width: 200) // bounded widthDefaults: 3 px tall, full width, pill shape (height / 2 radius), color = colorScheme.primary.
Cross-links
- Buttons —
Button.togglefor boolean filter chips - State Views —
LoadingStatewrapsCircularProgress - Cards —
HeroCardusesLinearProgressIndicatorinternally for its loading line