Custom variants
StyleVariants lets you define custom variant predicates that respond to any BuildContext condition — screen size, locale, directionality, inherited state, or anything else.
Basic usage
Section titled “Basic usage”Wrap a widget tree with StyleVariants to register custom variant names:
class CustomVariantsPage extends StatelessWidget { const CustomVariantsPage({super.key});
@override Widget build(BuildContext context) { return Scaffold( body: StyleVariants( variants: { 'compact': (context) => MediaQuery.sizeOf(context).width < 500, }, child: Style( 'flex flex-col gap-4 p-8 items-center', children: [ Style( 'text-sm text-gray-500', child: Text('Resize browser to < 500px for compact mode'), ), Style( 'bg-indigo-500 text-white font-bold py-4 px-8 rounded-lg compact:py-2 compact:px-4 compact:text-sm', child: Text('Adaptive Button'), ), ], ), ), ); }}Custom variants use the same prefix: syntax as built-in variants like hover: and dark:. When the predicate returns true, the prefixed classes are applied.
Custom breakpoints
Section titled “Custom breakpoints”Override Tailwind’s default breakpoints with StyleTheme:
class CustomBreakpointsPage extends StatelessWidget { const CustomBreakpointsPage({super.key});
@override Widget build(BuildContext context) { return Scaffold( body: StyleTheme( data: StyleThemeData( breakpoints: [ (name: 'tablet', width: 600), (name: 'desktop', width: 1000), ], ), child: Style( 'flex flex-col gap-4 p-8 items-center', children: [ Style( 'text-sm text-gray-500', child: Text('Resize to see breakpoints'), ), Style( 'bg-emerald-500 text-white font-bold p-4 rounded-lg tablet:p-6 desktop:p-8 tablet:text-lg desktop:text-xl', child: Text('Responsive with custom breakpoints'), ), ], ), ), ); }}Custom breakpoint names become available as responsive prefixes: tablet:, desktop:, etc.
Merging variants
Section titled “Merging variants”Use StyleVariants.merge to add variants while preserving those from ancestor widgets:
StyleVariants( variants: { 'compact': (context) => MediaQuery.sizeOf(context).width < 500, }, child: StyleVariants.merge( variants: { 'rtl': (context) => Directionality.of(context) == TextDirection.rtl, }, child: Style( 'p-4 compact:p-2 rtl:text-right', child: Text('Both variants available'), ), ),)Child variants override parent variants with the same name.
Variant ideas
Section titled “Variant ideas”Custom variants can respond to any context condition:
StyleVariants( variants: { // Screen-size based 'compact': (ctx) => MediaQuery.sizeOf(ctx).width < 500, 'tall': (ctx) => MediaQuery.sizeOf(ctx).height > 900,
// Locale/direction based 'rtl': (ctx) => Directionality.of(ctx) == TextDirection.rtl,
// Platform based 'ios': (ctx) => Theme.of(ctx).platform == TargetPlatform.iOS, 'android': (ctx) => Theme.of(ctx).platform == TargetPlatform.android,
// Accessibility 'high-contrast': (ctx) => MediaQuery.highContrastOf(ctx), 'reduce-motion': (ctx) => MediaQuery.disableAnimationsOf(ctx), }, child: myApp,)Combining with StyleTheme
Section titled “Combining with StyleTheme”Variants and themes are independent and compose naturally:
StyleTheme( data: StyleThemeData( colors: {'brand': {500: Color(0xFF316FF6)}}, ), child: StyleVariants( variants: { 'compact': (ctx) => MediaQuery.sizeOf(ctx).width < 500, }, child: Style( 'bg-brand-500 text-white p-6 compact:p-3 rounded-lg', child: Text('Themed + responsive'), ), ),)Custom colors from StyleTheme and custom variants from StyleVariants both apply to the same Style widget.