Field Formatting — cdx_field_formatting
cdx_field_formatting is a singleton dispatch registry for formatting field values. Every CDX surface that renders a date, number, currency, duration, or formatted JSON reads from the same FieldFormatter.instance — so changing the locale, date pattern, or timezone in one place re-formats every value in the app.
import 'package:cdx_field_formatting/cdx_field_formatting.dart';FieldFormatter
The singleton is populated synchronously on first access — no async initialization. The registry, timezone data, and built-in formatters are wired immediately.
// Typed convenience
FieldFormatter.instance.formatDate(area.createdAt);
FieldFormatter.instance.formatDateTime(area.updatedAt);
FieldFormatter.instance.formatTime(shift.startedAt);
FieldFormatter.instance.formatNumber(123456.789);
FieldFormatter.instance.formatInt(42);
FieldFormatter.instance.formatPercent(0.875); // 87.50%
FieldFormatter.instance.formatCurrency(42.5, 'USD');
FieldFormatter.instance.formatBytes(1234567); // 1.18 MB
FieldFormatter.instance.formatDuration(const Duration(minutes: 90));
FieldFormatter.instance.formatPhone('+15551234567');
FieldFormatter.instance.formatBool(true);
// Field-name dispatch — uses aliases / regex patterns / runtime-type fallback
FieldFormatter.instance.formatField('created_at', area.createdAt); // /_at$/ → datetime
FieldFormatter.instance.formatField('is_active', true); // /^is_/ → bool
FieldFormatter.instance.formatField('size_diameter', 12.5); // /^size_/ → decimal
// Widget version (Map / List → JsonConfigFormatter chip; DateTime → FormattedDateTime)
FieldFormatter.instance.formatFieldWidget(context, 'config', task.config);Settings — FormatSettings
FormatSettings is a reactive value (MobX Observable). Any widget inside an Observer that calls a format method auto-rebuilds when updateSettings is called.
FieldFormatter.instance.updateSettings(FormatSettings(
locale: 'en-US',
dateFormat: 'MMM d, y',
dateTimeFormat: 'MMM d, y h:mm a',
timeFormat: 'h:mm a',
timezone: 'America/Chicago',
currency: 'USD',
// ...
));
// Reset to FormatSettings.defaults
FieldFormatter.instance.reset();Custom registrations
// Register a custom formatter for a tag
FieldFormatter.instance.register<MyEnum>('my_enum', const MyEnumFormatter());
// Alias a field name to a tag
FieldFormatter.instance.aliasField('priority', 'my_enum');
// Bulk alias many fields at once
FieldFormatter.instance.aliasFields({
'priority': 'my_enum',
'severity': 'my_enum',
});
// Register a regex pattern (first match wins; checked when no exact alias exists)
FieldFormatter.instance.registerFieldPattern(RegExp(r'_email$'), FieldType.email.tag);
// Widget-producing formatter (for status chips, icons, etc.)
FieldFormatter.instance.registerWidget<bool>(
'bool_active',
const BoolChipFormatter(),
);Built-in field-name patterns
Auto-resolved when no exact alias exists:
| Pattern | Tag |
|---|---|
_at$ | datetime |
_on$ / _date$ | date |
_time$ | time |
^last_ | datetime |
^next_ | date |
_by$ | user_id |
_count$ / _size$ / _quantity$ / _qty$ / _number$ | integer |
^size_ | decimal |
_percent$ / _percentage$ | percent |
^is_ / ^has_ | bool |
FieldType tags
Built-in tags exposed as an enum so callers can avoid magic strings.
enum FieldType {
text, date, dateTime, dateRelative, time, dateLong,
boolean, booleanActive, integer, decimal, number,
currency, percentage, bytes, duration, phone,
email, url, uuid, userId, entityId, json, list,
}
// Use the .tag string when registering / aliasing
FieldFormatter.instance.aliasField('email_address', FieldType.email.tag);Named formatter constants
DateFormatters.standard, NumberFormatters.percent(), etc., are preconfigured Formatter<T> instances exposed via abstract holder classes. Pass them to typed convenience methods to override the default:
FieldFormatter.instance.formatDate(dt, format: DateFormatters.long); // April 18, 2026
FieldFormatter.instance.formatDate(dt, format: DateFormatters.relative); // 5 minutes ago
FieldFormatter.instance.formatDate(dt, format: DateFormatters.pattern('yyyy/MM/dd'));
FieldFormatter.instance.formatNumber(n, format: NumberFormatters.compact); // 1.2K
FieldFormatter.instance.formatCurrency(n, 'USD', format: CurrencyFormatters.accounting); // (42.50)| Holder | Notable members |
|---|---|
DateFormatters | standard, dateTime, time, long, medium, short, relative, dayOfWeek, monthYear, iso, pattern(...) |
NumberFormatters | standard, integer, percent({fractionDigits}), compact(), pattern(...) |
CurrencyFormatters | standard, compact, accounting |
BooleanFormatters | standard |
BytesFormatters | standard |
DurationFormatters | standard |
PhoneFormatters | standard |
Widget-producing formatters
| Class | Renders |
|---|---|
FormattedDateTime / FormattedDateTimeFormatter | Adaptive date/time block — stacked date+time on narrow, inline on wide |
BoolChipFormatter | Status chip for active/inactive booleans |
IconValueFormatter<T> | Icon + value (used for typed enums) |
JsonConfigFormatter | Compact "View JSON" chip with a tap-to-open pretty-printed dialog (default fallback for Map/List in formatFieldWidget) |
Locale loading
For non-default locales, call once at startup:
await FieldFormatter.instance.loadLocales(['en-US', 'de-DE', 'hi-IN']);Cross-links
- State Views — surface-level usage
- Pickers —
CdxDateRangePickerformats trigger label viaFieldFormatter.instance.formatDate