Skip to main content
Chromia UI provides a comprehensive breakpoint system and responsive utilities to help you build layouts that adapt to different screen sizes.

Breakpoint Tokens

Chromia UI includes four breakpoint sizes that follow common device dimensions:
BreakpointRangeConstant
Mobile0-599pxBreakpointTokens.mobile (600)
Tablet600-1023pxBreakpointTokens.tablet (1024)
Desktop1024-1439pxBreakpointTokens.desktop (1440)
Large Desktop1440px+BreakpointTokens.desktopLarge (1920)

Getting the Current Breakpoint

Using BuildContext Extension

The easiest way to get the current breakpoint is using the BuildContext extension:
@override
Widget build(BuildContext context) {
  final breakpoint = context.breakpoint;
  
  // Check specific breakpoint
  if (context.isMobile) {
    return MobileLayout();
  }
  
  // Check breakpoint ranges
  if (context.isMobileOrTablet) {
    return CompactLayout();
  }
  
  if (context.isDesktopOrLarger) {
    return WideLayout();
  }
  
  return DefaultLayout();
}

Available Extension Methods

context.breakpoint          // Returns current Breakpoint enum
context.isMobile            // true if mobile
context.isTablet            // true if tablet
context.isDesktop           // true if desktop
context.isDesktopLarge      // true if large desktop
context.isMobileOrTablet    // true if mobile or tablet
context.isDesktopOrLarger   // true if desktop or large desktop

Using BreakpointTokens Directly

import 'package:chromia_ui/chromia_ui.dart';

// From BuildContext
final breakpoint = BreakpointTokens.fromContext(context);

// From width value
final breakpoint = BreakpointTokens.fromWidth(1200);

ResponsiveBuilder Widget

The ResponsiveBuilder widget makes it easy to show different layouts based on the current breakpoint:
ResponsiveBuilder(
  mobile: MobileLayout(),
  tablet: TabletLayout(),
  desktop: DesktopLayout(),
  desktopLarge: LargeDesktopLayout(),
)

Fallback Behavior

If you don’t provide a widget for a specific breakpoint, ResponsiveBuilder will fall back to the next smaller size:
ResponsiveBuilder(
  mobile: CompactLayout(),
  desktop: WideLayout(),
  // Tablet falls back to mobile
  // Desktop large falls back to desktop
)

Responsive Patterns

1

Adaptive Grid Columns

Change the number of grid columns based on screen size:
@override
Widget build(BuildContext context) {
  final crossAxisCount = switch (context.breakpoint) {
    Breakpoint.mobile => 1,
    Breakpoint.tablet => 2,
    Breakpoint.desktop => 3,
    Breakpoint.desktopLarge => 4,
  };
  
  return GridView.builder(
    gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
      crossAxisCount: crossAxisCount,
      crossAxisSpacing: context.chromiaSpacing.medium,
      mainAxisSpacing: context.chromiaSpacing.medium,
    ),
    itemBuilder: (context, index) => ProductCard(),
  );
}
2

Responsive Spacing

Adjust spacing based on screen size:
@override
Widget build(BuildContext context) {
  final spacing = context.isMobileOrTablet 
    ? context.chromiaSpacing.small
    : context.chromiaSpacing.large;
  
  return Padding(
    padding: EdgeInsets.all(spacing),
    child: Column(
      spacing: spacing,
      children: [
        Header(),
        Content(),
        Footer(),
      ],
    ),
  );
}
3

Conditional Component Rendering

Show or hide components based on breakpoint:
@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: ChromiaAppBar(
      title: 'My App',
      leading: context.isMobileOrTablet
        ? IconButton(
            icon: Icon(Icons.menu),
            onPressed: () => Scaffold.of(context).openDrawer(),
          )
        : null,
    ),
    drawer: context.isMobileOrTablet ? ChromiaDrawer() : null,
    body: Row(
      children: [
        if (context.isDesktopOrLarger) ChromiaMiniDrawer(),
        Expanded(child: MainContent()),
      ],
    ),
  );
}
4

Responsive Typography

Scale text sizes based on screen size:
@override
Widget build(BuildContext context) {
  final textStyle = context.isMobile
    ? context.chromiaTypography.titleMedium
    : context.chromiaTypography.titleLarge;
  
  return ChromiaText(
    'Welcome to Chromia UI',
    style: textStyle,
  );
}

Complete Example

Here’s a complete example showing a responsive dashboard:
import 'package:chromia_ui/chromia_ui.dart';
import 'package:flutter/material.dart';

class ResponsiveDashboard extends StatelessWidget {
  const ResponsiveDashboard({super.key});

  @override
  Widget build(BuildContext context) {
    return ResponsiveBuilder(
      mobile: _MobileLayout(),
      tablet: _TabletLayout(),
      desktop: _DesktopLayout(),
    );
  }
}

class _MobileLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: EdgeInsets.all(context.chromiaSpacing.medium),
      children: [
        _StatCard(title: 'Users', value: '1,234'),
        SizedBox(height: context.chromiaSpacing.medium),
        _StatCard(title: 'Revenue', value: '\$12,345'),
        SizedBox(height: context.chromiaSpacing.medium),
        _StatCard(title: 'Orders', value: '567'),
      ],
    );
  }
}

class _TabletLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GridView.count(
      crossAxisCount: 2,
      padding: EdgeInsets.all(context.chromiaSpacing.medium),
      crossAxisSpacing: context.chromiaSpacing.medium,
      mainAxisSpacing: context.chromiaSpacing.medium,
      children: [
        _StatCard(title: 'Users', value: '1,234'),
        _StatCard(title: 'Revenue', value: '\$12,345'),
        _StatCard(title: 'Orders', value: '567'),
      ],
    );
  }
}

class _DesktopLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.all(context.chromiaSpacing.large),
      child: Row(
        children: [
          Expanded(
            child: _StatCard(title: 'Users', value: '1,234'),
          ),
          SizedBox(width: context.chromiaSpacing.large),
          Expanded(
            child: _StatCard(title: 'Revenue', value: '\$12,345'),
          ),
          SizedBox(width: context.chromiaSpacing.large),
          Expanded(
            child: _StatCard(title: 'Orders', value: '567'),
          ),
        ],
      ),
    );
  }
}

class _StatCard extends StatelessWidget {
  final String title;
  final String value;

  const _StatCard({required this.title, required this.value});

  @override
  Widget build(BuildContext context) {
    return ChromiaCard(
      child: Padding(
        padding: EdgeInsets.all(context.chromiaSpacing.large),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            ChromiaText(
              title,
              style: context.chromiaTypography.labelMedium,
              color: context.chromiaColors.textSecondary,
            ),
            SizedBox(height: context.chromiaSpacing.small),
            ChromiaText(
              value,
              style: context.chromiaTypography.displaySmall,
              color: context.chromiaColors.textPrimary,
            ),
          ],
        ),
      ),
    );
  }
}

Best Practices

Instead of:
if (BreakpointTokens.fromContext(context) == Breakpoint.mobile) {
  // ...
}
Use:
if (context.isMobile) {
  // ...
}
Use breakpoints together with spacing, typography, and other design tokens:
final padding = context.isMobile 
  ? context.chromiaSpacing.medium
  : context.chromiaSpacing.xLarge;
Always test your responsive layouts on:
  • Mobile phones (portrait and landscape)
  • Tablets (portrait and landscape)
  • Desktop screens (standard and large)
When layouts are significantly different across breakpoints, use ResponsiveBuilder instead of conditional logic.

Spacing System

Learn about consistent spacing tokens

Component Layout

See how components adapt responsively

Build docs developers (and LLMs) love