DACS
DACS brings Tailwind-inspired utility classes to Flutter. Write concise string expressions to define text styles, padding, colors, borders, shadows, transforms, gradients, and more.
Text('Hello, World!', style: 'text-2xl font-medium text-sky-500'.dText)
Features
- Zero-config — just install and use
- Tailwind v3 color palette — 22 colors × 11 shades
- Spacing scale — 0 to 384px in Tailwind increments
- Text utilities — size, weight, color, letter spacing, line height, decoration
- Background & border — colors, border width, border radius with directional variants
- Sizing, shadows & opacity — width, height, box shadows, opacity
- Position — inset-, top-, right-, bottom-, left-*
- Transform — scale, rotate, translate, skew
- Gradient — linear gradients from Tailwind color tokens
- Theme colors from
ColorScheme—text-primary,bg-surface,border-error - Arbitrary values —
text-[#ff0000],p-[20],w-[50%],rounded-[12] - Material widget extensions — style any Material widget:
.dButton(context),.dCheckbox(context),.dCard(context), etc. - WidgetState variants —
hover:,focus:,disabled:,pressed:,selected:,error:,dragged:,scrolledUnder: - Chained compound variants — combine any prefixes:
dark:hover:,dark:md:focus:,light:lg:disabled: - Dark/Light mode & responsive variants —
dark:,light:,sm:,md:,lg:,xl:,2xl: - Material 3 theme coverage — includes buttons, inputs, menus, navigation, drawers, badges, sliders, date pickers, and time pickers
Documentation
- Getting started
- Core concepts
- Utilities
- Material widgets
- Inputs
- Public API
- Widget support matrix
- Versioning policy
- Contributing guide
Installation
dependencies:
dacs: ^0.5.0
Usage
Configuration and compilation
DACS works without configuration, but you can enable diagnostics for unknown utilities and tune the parser cache:
Dacs.configure(
strictMode: false,
cacheSize: 500,
onUnknownUtility: (utility) {
debugPrint('Unknown DACS utility: $utility');
},
);
final sheet = DacsCompiler.compile('text-sm dark:md:hover:bg-red-500');
Compilation is context-free: DacsCompiler.compile only parses the string into
a DacsStyleSheet. Runtime values such as BuildContext, theme colors,
brightness, breakpoints, and widget states are applied later by methods such as
.dTextOf(context), .dBoxOf(context), and .dButton(context).
Text styles
Text('Heading', style: 'text-3xl font-bold text-gray-900'.dText)
Text('Body', style: 'text-base leading-relaxed text-gray-600'.dText)
Padding & Margin
Container(
padding: 'px-4 py-2'.dPads,
margin: 'mt-4'.dPads,
child: Text('Content', style: 'text-base'.dText),
)
Box decoration
Container(
decoration: 'bg-blue-500 rounded-lg shadow-md'.dBox,
child: Text('Button', style: 'text-white font-medium'.dText),
)
Gradients
Container(
decoration: 'bg-gradient-to-r from-sky-400 to-blue-600'.dBox,
child: Text('Gradient', style: 'text-white text-xl'.dText),
)
Shadows
Container(decoration: 'bg-white rounded-xl shadow-lg'.dBox)
// Or just the shadow list:
final shadows = 'shadow-lg'.dShadow;
Sizing
final (width, height) = 'w-64 h-48'.dSize;
Position (for Stack)
final (top, right, bottom, left) = 'inset-0'.dPosition;
Transform
Transform(
transform: 'scale-125 rotate-45'.dTransform,
child: Text('Styled'),
)
Dark / Light mode variants
// Resolves automatically from MediaQuery:
Text(
'Responsive text',
style: 'text-gray-900 dark:text-white'.dTextOf(context),
)
Container(
decoration: 'bg-white dark:bg-gray-900'.dBoxOf(context),
child: Text(
'Content',
style: 'text-base text-gray-600 dark:text-gray-300'.dTextOf(context),
),
)
Responsive variants
// Applies breakpoints based on screen width from MediaQuery:
Text(
'Responsive heading',
style: 'text-base sm:text-lg md:text-xl lg:text-2xl'.dTextOf(context),
)
Container(
padding: 'p-4 md:p-8 lg:p-12'.dPadsOf(context),
decoration: 'bg-white dark:bg-gray-900 rounded-lg'.dBoxOf(context),
child: Text(
'Content',
style: 'text-sm md:text-base'.dTextOf(context),
),
)
Theme colors
Use any ColorScheme key as a color — no need to import or reference the theme directly:
Text('Primary', style: 'text-primary font-bold'.dTextOf(context))
Container(decoration: 'bg-surface rounded-lg border-outline'.dBoxOf(context))
CheckboxTheme(
data: 'checked:bg-primary unchecked:bg-surface'.dCheckbox(context),
child: Checkbox(value: true, onChanged: (_) {}),
)
Supported keys: primary, onPrimary, primaryContainer, onPrimaryContainer, secondary, onSecondary, secondaryContainer, onSecondaryContainer, tertiary, onTertiary, tertiaryContainer, onTertiaryContainer, error, onError, errorContainer, onErrorContainer, surface, onSurface, surfaceVariant, onSurfaceVariant, outline, outlineVariant, inverseSurface, onInverseSurface, inversePrimary, shadow, scrim
Arbitrary values
Use square brackets for one-off values:
'text-[#ff0000]' // exact color
'bg-[rgb(255,0,0)]' // rgb syntax
'p-[20]' // 20px padding
'w-[50%]' // 50% width
'rounded-[12]' // 12px border radius
'opacity-[0.75]' // 75% opacity
'scale-[200]' // 2x scale
Material widget extensions
Style Material widgets via context-aware methods. WidgetState variant support
(hover:, focus:, disabled:, etc.) varies by adapter — see the table below.
ElevatedButton(
style: 'bg-primary text-white rounded-lg'.dButton(context),
onPressed: () {},
child: const Text('Submit'),
)
CheckboxTheme(
data: 'bg-primary hover:bg-primaryContainer'.dCheckbox(context),
child: Checkbox(value: true, onChanged: (_) {}),
)
CardTheme(
data: 'bg-surface rounded-xl shadow-md'.dCard(context),
child: Card(child: Text('Content', style: 'text-base'.dText)),
)
All 37 Material adapters are supported: dButton, dIconButton, dSegmentedButton, dCheckbox, dSwitch, dRadio, dChip, dBadge, dAppBar, dCard, dListTile, dTabBar, dBottomNav, dNavBar, dNavRail, dDrawer, dBottomAppBar, dInput, dProgress, dTooltip, dDivider, dScrollbar, dSnackBar, dDialog, dBottomSheet, dExpansionTile, dFab, dDataTable, dSearchBar, dMenu, dPopupMenu, dDropdownMenu, dSlider, dDatePicker, dTimePicker, dIcon, dShape.
For the detailed per-widget property matrix, see the widget support matrix.
TextField inputs
TextField.style and TextField.decoration are different Flutter APIs.
Use .dTextOf(context) for the typed text and .dInputOf(context) for the
input chrome: label, hint, helper, error, prefix/suffix, fill, density, padding,
and borders.
const classes = 'text-onSurface label-[Email] hint-[you@example.com] '
'helper-[Use your work email] filled dense bg-surface '
'border-outline focus:border-primary error:border-error '
'focus:error:border-primaryContainer rounded-lg p-4';
TextField(
style: classes.dTextOf(context),
decoration: classes.dInputOf(context),
)
Date and time picker themes
Picker adapters use explicit semantic color channels, so DACS does not guess hover, selected, disabled, or overlay colors for you. Declare every visual state you want to control:
Theme(
data: Theme.of(context).copyWith(
datePickerTheme:
'bg-surface text-onSurface rounded-lg shadow-md '
'date-header-bg-primary date-header-text-onPrimary '
'date-day-text-onSurface selected:date-day-bg-primary '
'hover:date-day-overlay-secondary date-today-text-secondary'
.dDatePicker(context),
timePickerTheme:
'bg-surface text-onSurface rounded-lg shadow-md '
'time-dial-bg-surfaceVariant time-dial-hand-primary '
'time-hour-minute-bg-surfaceVariant '
'selected:time-hour-minute-bg-secondary '
'time-hour-minute-text-onSurface '
'selected:time-hour-minute-text-onSecondary'
.dTimePicker(context),
),
child: const SizedBox.shrink(),
)
WidgetState variants
For Material widgets, use interactive state variants:
ElevatedButton(
style: 'bg-primary hover:bg-primaryContainer disabled:bg-surface
rounded-lg hover:rounded-xl'.dButton(context),
onPressed: () {},
child: const Text('Submit'),
)
State order: base → disabled → pressed → hover → focus → selected → error → dragged → scrolledUnder.
Shape variants (hover:rounded-xl, pressed:rounded-sm) resolve dynamically via _stateProp.
Chained compound variants
Combine any variant prefixes with ::
// Applies only in dark mode AND when hovered
Text(
'Styled text',
style: 'text-white dark:hover:text-primary'.dTextOf(context),
)
// Triple compound: dark mode, medium breakpoint, hover
Container(
decoration: 'bg-primary dark:md:hover:bg-error'.dBoxOf(context),
)
Parsed style access
final sheet = 'text-lg font-bold text-red-600 dark:text-white'.dStyle;
final base = sheet.base;
print(base.fontSize); // 18
print(base.fontWeight); // FontWeight.w700
print(base.color); // Color(0xFFDC2626)
final resolved = sheet.resolveFor(context); // DacsResolvedStyle
Extension methods
Simple getters (no context)
These parse classes and convert immediately. Useful when you don't need variant resolution.
| Getter | Returns |
|---|---|
.dText |
TextStyle |
.dPads |
EdgeInsets |
.dBox |
BoxDecoration |
.dStyle |
DacsStyleSheet |
.dBase |
DacsStyle |
.dShadow |
List<BoxShadow> |
.dSize |
(double?, double?) |
.dFixedSize |
Size? |
.dLayout |
DacsLayoutStyle |
.dPosition |
(double?, double?, double?, double?) |
.dTransform |
Matrix4 |
.dGradient |
LinearGradient? |
.dBorder |
BoxBorder? |
.dBorderSide |
BorderSide? |
.dRadius |
BorderRadiusGeometry? |
.dConstraints |
BoxConstraints? |
.dAlignment |
AlignmentGeometry? |
.dShapeBorder |
ShapeBorder? |
Context-aware methods (resolve variants)
These accept a BuildContext to resolve dark/light mode, responsive breakpoints, and theme colors from MediaQuery / Theme.
| Method | Returns |
|---|---|
.dTextOf(context) |
TextStyle |
.dPadsOf(context) |
EdgeInsets |
.dMarginOf(context) |
EdgeInsets |
.dBoxOf(context) |
BoxDecoration |
.dStyleOf(context) |
DacsResolvedStyle |
.dShadowOf(context) |
List<BoxShadow> |
.dSizeOf(context) |
(double?, double?) |
.dFixedSizeOf(context) |
Size? |
.dLayoutOf(context) |
DacsLayoutStyle |
.dPositionOf(context) |
(double?, double?, double?, double?) |
.dTransformOf(context) |
Matrix4 |
.dGradientOf(context) |
LinearGradient? |
.dBorderOf(context) |
BoxBorder? |
.dBorderSideOf(context) |
BorderSide? |
.dRadiusOf(context) |
BorderRadiusGeometry? |
.dConstraintsOf(context) |
BoxConstraints? |
.dAlignmentOf(context) |
AlignmentGeometry? |
.dShapeBorderOf(context) |
ShapeBorder? |
Material widget extensions
These accept a BuildContext and return Material theme data with variant resolution.
WidgetState support is marked per method.
For property-level support, see the
widget support matrix.
| Method | Returns | WidgetState |
|---|---|---|
.dButton(context) |
ButtonStyle |
full |
.dIconButton(context) |
IconButtonThemeData |
full through ButtonStyle |
.dSegmentedButton(context) |
SegmentedButtonThemeData |
full through ButtonStyle |
.dCheckbox(context) |
CheckboxThemeData |
partial |
.dSwitch(context) |
SwitchThemeData |
partial |
.dRadio(context) |
RadioThemeData |
partial |
.dChip(context) |
ChipThemeData |
only color |
.dBadge(context) |
BadgeThemeData |
— |
.dScrollbar(context) |
ScrollbarThemeData |
partial |
.dNavBar(context) |
NavigationBarThemeData |
only label |
.dNavRail(context) |
NavigationRailThemeData |
— |
.dDrawer(context) |
DrawerThemeData |
— |
.dBottomAppBar(context) |
BottomAppBarThemeData |
— |
.dDataTable(context) |
DataTableThemeData |
partial |
.dSearchBar(context) |
SearchBarThemeData |
partial |
.dMenu(context) |
MenuStyle |
partial |
.dPopupMenu(context) |
PopupMenuThemeData |
partial |
.dDropdownMenu(context) |
DropdownMenuThemeData |
partial |
.dSlider(context) |
SliderThemeData |
partial |
.dDatePicker(context) |
DatePickerThemeData |
partial |
.dTimePicker(context) |
TimePickerThemeData |
partial |
.dAppBar(context) |
AppBarTheme |
— |
.dCard(context) |
CardTheme |
— |
.dListTile(context) |
ListTileThemeData |
— |
.dTabBar(context) |
TabBarTheme |
— |
.dBottomNav(context) |
BottomNavigationBarThemeData |
— |
.dInput(context) / .dInputOf(context) |
InputDecoration |
focus, disabled, error, focus:error border mappings |
.dProgress(context) |
ProgressIndicatorThemeData |
— |
.dTooltip(context) |
TooltipThemeData |
— |
.dDivider(context) |
DividerThemeData |
— |
.dSnackBar(context) |
SnackBarThemeData |
— |
.dDialog(context) |
DialogTheme |
— |
.dBottomSheet(context) |
BottomSheetThemeData |
— |
.dExpansionTile(context) |
ExpansionTileThemeData |
— |
.dFab(context) |
FloatingActionButtonThemeData |
— |
.dIcon(context) |
IconThemeData |
— |
.dShape(context) |
ShapeDecoration |
— |
Supported classes
Typography
| Class | Flutter property |
|---|---|
text-xs … text-9xl |
fontSize (12 … 128) |
font-thin … font-black |
fontWeight (100 … 900) |
leading-3 … leading-10 |
height (line height) |
leading-none … leading-loose |
height (relative) |
tracking-tighter … tracking-widest |
letterSpacing |
italic / not-italic |
fontStyle |
underline / line-through / no-underline |
textDecoration |
decoration-solid / double / dotted / dashed / wavy |
textDecorationStyle |
decoration-{1..} |
textDecorationThickness |
decoration-{color}-{shade} |
textDecorationColor |
Colors (text, background, border, decoration)
Format: {prefix}-{color}-{shade}
'text-sky-500' // text color
'bg-blue-200' // background color
'border-red-600' // border color
'decoration-green-500' // text decoration color
Supported colors: slate, gray, zinc, neutral, stone, red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose
Shades: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950
Also: text-black, text-white, text-transparent
Spacing
| Class | Output |
|---|---|
p-4 |
EdgeInsets.all(16) |
px-4 |
EdgeInsets.symmetric(horizontal: 16) |
py-2 |
EdgeInsets.symmetric(vertical: 8) |
pt-4, pr-4, pb-4, pl-4 |
Directional padding |
m-*, mx-*, my-*, mt-*, mr-*, mb-*, ml-* |
Same for margin |
Spacing keys: 0, px, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 96
Border
| Class | Output |
|---|---|
rounded-none |
BorderRadius.circular(0) |
rounded-sm |
BorderRadius.circular(2) |
rounded |
BorderRadius.circular(4) |
rounded-md / rounded-lg / rounded-xl / rounded-2xl / rounded-3xl |
6 / 8 / 12 / 16 / 24 |
rounded-full |
BorderRadius.circular(9999) |
rounded-t-lg, rounded-b-sm, rounded-l-md, rounded-r-xl |
Directional |
rounded-tl-lg, rounded-tr-lg, rounded-bl-lg, rounded-br-lg |
Corner-specific |
border |
Border.all(width: 1) |
border-2 … border-8 |
Border.all(width: size) |
Sizing & opacity
'w-64' // width: 256
'h-32' // height: 128
'w-full' // width: double.infinity
'opacity-50' // opacity: 0.5
Shadows
| Class | BoxShadows |
|---|---|
shadow-sm |
1 shadow (subtle) |
shadow |
2 shadows (default) |
shadow-md / shadow-lg / shadow-xl / shadow-2xl |
Increasing blur/spread |
shadow-inner |
Inset shadow |
shadow-none |
Empty list |
Position
| Class | Properties |
|---|---|
inset-0 |
top=0, right=0, bottom=0, left=0 |
inset-x-4 |
left=16, right=16 |
inset-y-2 |
top=8, bottom=8 |
top-4, right-4, bottom-4, left-4 |
Individual inset |
Transform
| Class | Property |
|---|---|
scale-125 |
scaleX=1.25, scaleY=1.25 |
scale-x-150 |
scaleX=1.5 |
scale-y-75 |
scaleY=0.75 |
rotate-45 |
rotateDegrees=45 |
translate-x-4 |
translateX=16 |
translate-y-2 |
translateY=8 |
skew-x-12 |
skewX=12 |
skew-y-6 |
skewY=6 |
Gradient
'bg-gradient-to-r from-red-500 to-blue-600'
'bg-gradient-to-tl from-amber-400 via-orange-500 to-red-600'
Directions: to-r, to-l, to-t, to-b, to-tr, to-tl, to-br, to-bl
Variants
Prefix any class with a variant to scope it:
| Variant | Trigger |
|---|---|
dark: |
Applies when MediaQuery.platformBrightness == Brightness.dark |
light: |
Applies when MediaQuery.platformBrightness == Brightness.light |
sm: |
Applies at min-width: 640px |
md: |
Applies at min-width: 768px |
lg: |
Applies at min-width: 1024px |
xl: |
Applies at min-width: 1280px |
2xl: |
Applies at min-width: 1536px |
hover: |
WidgetState.hovered |
focus: |
WidgetState.focused |
active: / pressed: |
WidgetState.pressed |
disabled: |
WidgetState.disabled |
selected: |
WidgetState.selected |
error: |
WidgetState.error |
dragged: |
WidgetState.dragged |
scrolledUnder: |
WidgetState.scrolledUnder |
Resolution order (Material contexts): base → disabled → pressed → hover → focus → selected → error → dragged → scrolledUnder.
Chained compound variants: combine multiple prefix types with :.
'dark:hover:text-white' // dark mode + hover
'light:md:bg-primary' // light mode + md breakpoint
'dark:lg:focus:border-error' // dark + lg + focus
Compound variants match only when ALL conditions are met. WidgetState conditions re-map to simple keys for Material widget resolution.
Additional information
- Report issues
- View source
- Licensed under the MIT License
Libraries
- dacs
- DACS — Tailwind-like utility classes for Flutter.