Skip to content

<MediaQuery>

Overview

The <MediaQuery> component exposes Flutter's MediaQuery data to child widgets via dependencies, making screen size, orientation, padding, and accessibility settings available in your XML markup. It's essential for building responsive layouts that adapt to different screen sizes and device capabilities.

The <MediaQuery> component provides real-time access to:

  • Screen dimensions: Width, height, and responsive breakpoints (small/medium/large)
  • View insets: Keyboard and system UI overlays
  • View padding: Safe area insets for notches, status bars, and navigation bars
  • Platform settings: Brightness, orientation, text scaling, and accessibility features

All data is exposed through a configurable variable name (default: mediaQuery) that can be referenced in child widget expressions.

Use Cases

  • Building responsive layouts that adapt to screen size
  • Creating different UIs for mobile, tablet, and desktop
  • Handling keyboard visibility and adjusting UI accordingly
  • Respecting safe area insets (notches, system UI)
  • Adapting to device orientation changes
  • Supporting accessibility features (bold text, high contrast)
  • Implementing breakpoint-based designs

Attributes

Name Type Description Required Default
varName String The variable name used to access media query data in dependencies No "mediaQuery"
smallMaxWidth int Maximum width (in logical pixels) for "small" layout classification No 640
mediumMaxWidth int Maximum width (in logical pixels) for "medium" layout classification. Larger screens are "large" No 1024
dependenciesScope String How to scope dependencies: "copy" (default), "inherit", or "isolate" No "copy"
key Key Widget key for controlling widget identity No null
for String The name of the parent's attribute that will be assigned this component No null
visible bool Controls widget visibility No true

Available Properties

When using the default varName of "mediaQuery", the following properties are available:

Screen Size

Property Type Description
mediaQuery.size.width double Screen width in logical pixels
mediaQuery.size.height double Screen height in logical pixels
mediaQuery.size.layout String "small", "medium", or "large" based on width breakpoints

View Insets

View insets represent the portions of the screen covered by system UI (like the keyboard):

Property Type Description
mediaQuery.viewInsets.left double Left inset in logical pixels
mediaQuery.viewInsets.top double Top inset in logical pixels
mediaQuery.viewInsets.right double Right inset in logical pixels
mediaQuery.viewInsets.bottom double Bottom inset (e.g., keyboard height)
mediaQuery.viewInsets.horizontal double Sum of left + right insets
mediaQuery.viewInsets.vertical double Sum of top + bottom insets

View Padding

View padding represents safe area insets (notches, status bars, navigation bars):

Property Type Description
mediaQuery.viewPadding.left double Left padding in logical pixels
mediaQuery.viewPadding.top double Top padding (status bar)
mediaQuery.viewPadding.right double Right padding in logical pixels
mediaQuery.viewPadding.bottom double Bottom padding (navigation bar)
mediaQuery.viewPadding.horizontal double Sum of left + right padding
mediaQuery.viewPadding.vertical double Sum of top + bottom padding

Platform Settings

Property Type Description
mediaQuery.orientation String "portrait" or "landscape"
mediaQuery.platformBrightness Brightness Brightness.light or Brightness.dark
mediaQuery.boldText bool Whether bold text accessibility setting is enabled
mediaQuery.highContrast bool Whether high contrast accessibility setting is enabled
mediaQuery.disableAnimations bool Whether reduce motion accessibility setting is enabled

Examples

Basic Responsive Layout

<MediaQuery>
  <Column>
    <Text>Screen width: ${mediaQuery.size.width}px</Text>
    <Text>Screen height: ${mediaQuery.size.height}px</Text>
    <Text>Layout: ${mediaQuery.size.layout}</Text>
  </Column>
</MediaQuery>

Conditional Layout Based on Screen Size

<MediaQuery>
  <Column>
    <!-- Mobile layout -->
    <Column visible="${mediaQuery.size.layout == 'small'}">
      <Text>Mobile View</Text>
      <ListView>...</ListView>
    </Column>

    <!-- Tablet layout -->
    <Row visible="${mediaQuery.size.layout == 'medium'}">
      <Text>Tablet View</Text>
      <SidePanel/>
      <MainContent/>
    </Row>

    <!-- Desktop layout -->
    <Row visible="${mediaQuery.size.layout == 'large'}">
      <Text>Desktop View</Text>
      <NavigationRail/>
      <MainContent/>
      <DetailPanel/>
    </Row>
  </Column>
</MediaQuery>

Custom Breakpoints

<MediaQuery smallMaxWidth="480" mediumMaxWidth="1280">
  <Container>
    <Text visible="${mediaQuery.size.layout == 'small'}">
      Mobile (≤480px)
    </Text>
    <Text visible="${mediaQuery.size.layout == 'medium'}">
      Tablet (481px-1280px)
    </Text>
    <Text visible="${mediaQuery.size.layout == 'large'}">
      Desktop (>1280px)
    </Text>
  </Container>
</MediaQuery>

Respecting Safe Area Insets

<MediaQuery>
  <Column>
    <!-- Add padding for notches/status bar -->
    <SizedBox height="${mediaQuery.viewPadding.top}"/>

    <AppBar title="My App"/>

    <Expanded>
      <ListView>...</ListView>
    </Expanded>

    <!-- Add padding for navigation bar -->
    <SizedBox height="${mediaQuery.viewPadding.bottom}"/>
  </Column>
</MediaQuery>

Handling Keyboard Visibility

<MediaQuery>
  <Column>
    <Expanded>
      <ListView>...</ListView>
    </Expanded>

    <!-- Push input field above keyboard -->
    <Container>
      <TextField hint="Type a message"/>
      <SizedBox height="${mediaQuery.viewInsets.bottom}"/>
    </Container>
  </Column>
</MediaQuery>

Orientation-Based Layout

<MediaQuery>
  <Column visible="${mediaQuery.orientation == 'portrait'}">
    <Text>Portrait Mode</Text>
    <Image aspectRatio="3/4"/>
  </Column>

  <Row visible="${mediaQuery.orientation == 'landscape'}">
    <Text>Landscape Mode</Text>
    <Image aspectRatio="16/9"/>
  </Row>
</MediaQuery>

Accessibility Support

<MediaQuery>
  <Column>
    <Text 
      style="fontSize: ${mediaQuery.boldText ? 18 : 16}; fontWeight: ${mediaQuery.boldText ? 'bold' : 'normal'}">
      Accessible Text
    </Text>

    <Container visible="${!mediaQuery.disableAnimations}">
      <AnimatedWidget/>
    </Container>

    <Container visible="${mediaQuery.disableAnimations}">
      <StaticWidget/>
    </Container>
  </Column>
</MediaQuery>

Custom Variable Name

<MediaQuery varName="mq">
  <Column>
    <Text>Width: ${mq.size.width}</Text>
    <Text>Layout: ${mq.size.layout}</Text>
    <Text>Orientation: ${mq.orientation}</Text>
  </Column>
</MediaQuery>

Grid Layout with Responsive Columns

<MediaQuery>
  <GridView 
    crossAxisCount="${mediaQuery.size.layout == 'small' ? 2 : mediaQuery.size.layout == 'medium' ? 3 : 4}">
    <forEach var="item" in="${items}">
      <Card>
        <Text>${item.name}</Text>
      </Card>
    </forEach>
  </GridView>
</MediaQuery>

Bottom Sheet with Keyboard Handling

<MediaQuery>
  <Container>
    <Column>
      <Text>Enter your details</Text>
      <TextField hint="Name"/>
      <TextField hint="Email"/>

      <!-- Spacer that grows when keyboard appears -->
      <SizedBox height="${mediaQuery.viewInsets.bottom}"/>

      <ElevatedButton onPressed="submit">
        <Text>Submit</Text>
      </ElevatedButton>
    </Column>
  </Container>
</MediaQuery>

Breakpoint Guidelines

The default breakpoints follow common responsive design patterns:

  • Small (≤640px): Mobile phones in portrait
  • Medium (641px-1024px): Large phones, small tablets, tablets in portrait
  • Large (>1024px): Tablets in landscape, desktops, large screens

You can customize these breakpoints using smallMaxWidth and mediumMaxWidth attributes to match your design system.

Common Patterns

Responsive Padding

<MediaQuery>
  <Container padding="${mediaQuery.size.layout == 'small' ? 16 : mediaQuery.size.layout == 'medium' ? 24 : 32}">
    <Text>Content with responsive padding</Text>
  </Container>
</MediaQuery>

Adaptive Font Sizes

<MediaQuery>
  <Text style="fontSize: ${mediaQuery.size.layout == 'small' ? 14 : mediaQuery.size.layout == 'medium' ? 16 : 18}">
    Responsive text size
  </Text>
</MediaQuery>

Two-Column Layout for Large Screens

<MediaQuery>
  <Row visible="${mediaQuery.size.layout == 'large'}">
    <Expanded flex="1">
      <Sidebar/>
    </Expanded>
    <Expanded flex="3">
      <MainContent/>
    </Expanded>
  </Row>

  <Column visible="${mediaQuery.size.layout != 'large'}">
    <MainContent/>
  </Column>
</MediaQuery>

Best Practices

Place MediaQuery High in Widget Tree

Place <MediaQuery> near the root of your widget tree so all children have access:

<Scaffold>
  <MediaQuery for="body">
    <!-- All children can access mediaQuery -->
    <Column>
      <Header/>
      <Content/>
      <Footer/>
    </Column>
  </MediaQuery>
</Scaffold>

Use Layout Categories Over Exact Pixels

<!-- Good: Uses layout categories -->
<Text visible="${mediaQuery.size.layout == 'small'}">Mobile</Text>

<!-- Less ideal: Hard-coded pixel values -->
<Text visible="${mediaQuery.size.width < 640}">Mobile</Text>

Consider Accessibility Settings

<MediaQuery>
  <Text 
    style="fontSize: ${mediaQuery.boldText ? 18 : 16}">
    ${mediaQuery.boldText ? 'Accessibility: Bold text enabled' : 'Normal text'}
  </Text>
</MediaQuery>

Handle Orientation Changes

<MediaQuery>
  <Container>
    <Column visible="${mediaQuery.orientation == 'portrait'}">
      <PortraitLayout/>
    </Column>
    <Row visible="${mediaQuery.orientation == 'landscape'}">
      <LandscapeLayout/>
    </Row>
  </Container>
</MediaQuery>

Performance Considerations

  • <MediaQuery> is lightweight and rebuilds only when media query data changes
  • Changes trigger when: screen rotates, keyboard appears/disappears, window resizes, or accessibility settings change
  • Consider placing multiple <MediaQuery> components for isolated subtrees if needed
  • The component doesn't create new MediaQueryData - it reads from Flutter's existing MediaQuery

See Also

  • <LayoutBuilder> - For constraint-based layouts
  • <OrientationBuilder> - For orientation-specific layouts
  • <ValueListener> - For listening to value changes