<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 existingMediaQuery
See Also
<LayoutBuilder>- For constraint-based layouts<OrientationBuilder>- For orientation-specific layouts<ValueListener>- For listening to value changes