Badges, Chips & Banners
Three families for status communication:
| Family | Use |
|---|---|
StatusBadge | Small status pill — entity status, severity, count |
CdxChip | Filter / token chip — single-line, dismissible, selectable |
Banner | Full-width status notice — page-level alerts, success / warning / critical / info |
UnderConstructionOverlay | App-wide flagged-feature banner |
StatusBadge
Named
StatusBadge(notBadge) to avoid collision with Flutter's built-inBadgewidget.
A configurable pill with shape, size, color scheme, and optional icon / child / onTap / tooltip.
Color schemes
StatusBadgeColorScheme is a sealed strategy. Use a named factory or construct one inline.
StatusBadge.primary(label: 'Active', icon: FluentIcons.checkmark_24_regular)
StatusBadge.secondary(label: 'Pending')
StatusBadge.tertiary(label: 'Review')
StatusBadge.error(label: 'Failed', icon: FluentIcons.error_circle_24_regular)
StatusBadge.neutral(label: 'Archived')
// Tinted around any base color (subtle bg + faint border + full-strength fg)
StatusBadge.tinted(
CdxConfig.of(context).warningOf(Theme.of(context).colorScheme),
label: 'Expiring soon',
shape: StatusBadgeShape.pill,
)
// Compact tinted — for inline metadata (BETA, v0.1.2, tags)
StatusBadge.compact(
CdxConfig.of(context).infoOf(Theme.of(context).colorScheme),
label: 'BETA',
)
// Count pill — neutral pill with the count as label
StatusBadge.count(unreadCount)Shapes
enum StatusBadgeShape { rectangle, pill, rounded }| Shape | Radius |
|---|---|
rectangle | controlBorderRadius (4) |
pill | 999 (fully rounded) |
rounded | containerBorderRadius (8) |
Sizes
enum StatusBadgeSize { small, medium }| Size | Text style | Icon |
|---|---|---|
small | labelSmall w600 | 16 px |
medium | bodySmall w500 | 18 px |
Custom colors
For a one-off palette, build a StatusBadgeColors:
StatusBadge(
label: 'Custom',
colorScheme: const StatusBadgeColorScheme.explicit(StatusBadgeColors(
background: Color(0xfff3e8ff),
foreground: Color(0xff6d28d9),
border: Color(0xffa78bfa),
)),
)CdxChip
The canonical filter / token chip across CDX. Two recurring shapes covered by one widget:
// Filter chip
CdxChip(
label: 'Active',
icon: FluentIcons.checkmark_24_regular,
selected: filter.activeOnly,
onTap: () => filter.toggleActive(),
)
// Dismissible token (pairs the chip with CdxDismissAffordance internally)
CdxChip(
label: assignee.name,
onDeleted: () => removeAssignee(assignee),
deleteTooltip: 'Remove ${assignee.name}',
)
// Combined — selectable AND dismissible
CdxChip(
label: 'Urgent',
selected: tag.selected,
onTap: () => toggleTag(tag),
onDeleted: () => removeTag(tag),
)Density
enum CdxChipSize { small, regular, compact }| Size | Vertical | Text style | Use |
|---|---|---|---|
small | tight | labelSmall | Inline metadata, dense lists (default) |
regular | roomier | labelMedium | Standard chip rows that need more breathing room |
compact | aligns to compactControlSize (32 px) | labelMedium | When chips share a row with compact form controls |
Rich labels
For mixed-style spans (bold field name + value, async-loading entity name), pass a labelBuilder:
CdxChip(
label: '...', // ignored when labelBuilder is set
labelBuilder: (context) => Text.rich(TextSpan(children: [
const TextSpan(text: 'Site: ', style: TextStyle(fontWeight: FontWeight.w600)),
TextSpan(text: site.name),
])),
)Banner
Full-width status banner card. Five named factories cover the standard severities; pass backgroundColor / foregroundColor to override.
Banner.warning(
message: 'Equipment requires calibration before next batch.',
trailing: TextButton(onPressed: _openCalibration, child: const Text('Calibrate')),
)
Banner.critical(message: 'Unable to reach inventory service.')
Banner.success(message: 'Batch released successfully.')
Banner.info(message: 'New comments on this lot.')
Banner.neutral(message: 'Audit completed last week.')BannerType palette pulls from CdxConfig:
| Type | Background | Foreground |
|---|---|---|
warning | warningContainerOf | onWarningContainerOf |
critical | criticalContainerOf (= errorContainer) | onCriticalContainerOf |
success | successContainerOf | onSuccessContainerOf |
info | secondaryContainer | onSecondaryContainer |
neutral | neutralContainerOf | onNeutralContainerOf |
UnderConstructionOverlay
App-wide registry for "under construction" banners on partially-built pages. Bootstrap toggles flags; child widgets wrap themselves and render the banner only when enabled.
// At app startup
UnderConstructionController.enable('settings.reports', message: 'Custom reports launching next sprint.');
UnderConstructionController.disable('inbox.batch-actions');
// In the widget tree
UnderConstructionOverlay(
id: 'settings.reports',
child: ReportsSettingsPage(),
)When the controller has no entry for id, the banner is hidden and the child renders directly.
| Param | Default |
|---|---|
id | required — controller key |
defaultMessage | 'Under construction' |
defaultSubtitle | "We're still polishing this area. Check back soon." |
icon | FluentIcons.wrench_24_regular |
expandChild | true (Expanded(child)) |