Styling
Form Kit controls draw with vyuh_cdx_ui and are themed through CdxConfig, the CDX ThemeExtension. The look of every field (text fields, dropdown triggers, pickers, switch rows, field labels and section captions) comes from one token set, CdxFieldStyle, with two presets.
Classic and refined
CdxConfig.classic() (default) | CdxConfig.refined() | |
|---|---|---|
| Field style | CdxFieldStyle() | CdxFieldStyle.refined() |
| Label | Floating inside the outline, muted tone | Above the field, 14/20 w500, strong tone, 4 px gap |
| Field height | controlHeight (36 px) | 36 px, 12 px horizontal padding |
| Radius | controlBorderRadius (4 px) | 6 px |
| Outline | Strong (outline) | Soft (outlineVariant) |
| Focus ring | 1 px | 1.5 px |
| Text | Theme default | 16/20 value, 12/16 notes and captions |
| Type scale | Your TextTheme as given | CdxTypeScale.refined(): 16/20 body on a 4 px baseline |
| Spacing | Hand-picked values | Steps of CdxSpacing |
| Switch rows | Platform size | Fit into 24 px |
| Use for | Existing apps; nothing changes | Designers, blueprints and dense data-entry forms |
CdxConfig.classic() is the same as const CdxConfig(), token for token, so apps that never pass a config keep their look. The refined preset differs from classic in fieldStyle, typeScale and the spacing tokens; control height, icon size, shapes and colours are the same.
The refined type scale
CdxTypeScale.refined() resizes your TextTheme when createCdxTheme builds the theme; your font family, weights and colours stay. Every line height is a multiple of 4 px, so stacked text and controls keep a steady vertical rhythm.
| Step | Size / line | Slots |
|---|---|---|
| caption | 12 / 16 | labelSmall, notes, section captions |
| small | 14 / 20 | bodySmall, labelMedium, labelLarge, titleSmall, field labels |
| body | 16 / 20 | bodyMedium, titleMedium, field values |
| lead | 18 / 24 | bodyLarge, titleLarge |
| title | 20 / 24 | headlineSmall |
| heading | 24 / 28 | headlineMedium |
| headline | 28 / 32 | headlineLarge |
| display, hero, jumbo | 32/36, 40/44, 48/52 | displaySmall, displayMedium, displayLarge |
The spacing scale
CdxSpacing is the set of distances layout gaps and paddings take: 4, 8, 12, 16, 24, 32 and 48 px. It grows by more the further up it goes, so the closer two things sit, the more closely they belong together.
| Step | px | Used for |
|---|---|---|
xs | 4 | a label and its field |
sm | 8 | properties within one group |
md | 12 | padding inside a card; a field's horizontal padding |
lg | 16 | fields in a form, sections, container padding |
xl, xxl, xxxl | 24, 32, 48 | groups of sections, page-level breaks |
import 'package:material_ui/material_ui.dart';
import 'package:vyuh_cdx_ui/vyuh_cdx_ui.dart';
// Existing apps: no change, classic look.
final classic = createCdxTheme(colorScheme: scheme, textTheme: textTheme);
// Form Kit apps: refined look, with token overrides on top.
final refined = createCdxTheme(
colorScheme: scheme,
textTheme: textTheme,
config: const CdxConfig.refined(
primary: Color(0xFF1F5FAF),
fieldStyle: CdxFieldStyle.refined(height: 30),
),
);
// Mix: classic chrome, labels above only.
const labelsAbove = CdxConfig(
fieldStyle: CdxFieldStyle(labelPlacement: CdxFieldLabelPlacement.above),
);Read the active look inside a widget:
final style = CdxConfig.of(context).fieldStyle;
if (style.height != null) {
// fixed-height fields
}CdxFieldStyle tokens
| Token | Type | Classic | Refined |
|---|---|---|---|
labelPlacement | CdxFieldLabelPlacement (floating, above) | floating | above |
labelTone | CdxFieldLabelTone (muted, strong) | muted | strong |
labelStyle | TextStyle? | null | 12 px, w500 |
labelGap | double | 6 | 6 |
borderRadius | BorderRadius? | null (uses controlBorderRadius) | 6 px |
outline | CdxFieldOutline (strong, soft) | strong | soft |
focusWidth | double | 1 | 1.5 |
height | double? | null (intrinsic) | 32 |
horizontalPadding | double? | null | 10 |
textStyle | TextStyle? | null | 13 px |
noteStyle | TextStyle? | null | 11 px |
captionStyle | TextStyle? | null | 11 px, w600, 0.88 letter spacing |
toggleHeight | double? | null | 20 |
Text tokens are partial styles layered over the matching TextTheme slot, so a brand's typography still comes through. null means "keep the Material or caller default". Both CdxConfig and CdxFieldStyle support copyWith, lerp and value equality, so overrides compose:
final config = const CdxConfig.refined().copyWith(
fieldStyle: const CdxFieldStyle.refined().copyWith(focusWidth: 2),
);Supporting widgets
| Widget | Use |
|---|---|
CdxLabeledField(label:, child:, hasError:, active:, labelStyle:) | Draws a label above a field and merges both into one accessibility node, so the field keeps its label as its accessible name. The label takes the primary colour while focus is inside and the error colour when hasError. |
CdxSectionCaption(text) | A group caption styled by the active captionStyle. |
CdxFieldAffixButton(icon:, onPressed:, tooltip:) | A prefix or suffix button inside a field. With a fixed field height it is a square of that height, so it cannot grow the field. |
InputDecoration.withoutLabel() | An extension that strips label / labelText from a decoration, for fields that draw their label above. |
Not affected by the presets
The Material DropdownMenu focus ring (2 px), non-field radii (buttons, cards, dialogs, data tables) and CdxSlider look the same in both presets.
The rest of CdxConfig is documented with vyuh_cdx_ui.