---
name: layout-responsive
description: MUI layout components and responsive design patterns
triggers:
- layout
- Grid
- Stack
- responsive
- breakpoints
- Container
- useMediaQuery
allowed-tools:
- Read
- Glob
- Grep
- Write
- Edit
globs:
- "*.tsx"
- "*.jsx"
---
# MUI Layout and Responsive Design
## Grid v2
MUI v6 ships Grid v2 as default (imported from `@mui/material/Grid`). The `size` prop
replaces the old `xs`/`sm`/`md` props. Grid v2 always uses CSS grid internally and no
longer requires the `item` prop — every direct child of a `container` is a grid item.
### Basic grid
```tsx
import Grid from '@mui/material/Grid';
import Paper from '@mui/material/Paper';
Full width header
Main content (full on mobile, 8/12 on desktop)
Sidebar (full on mobile, 4/12 on desktop)
```
### size values
```tsx
// Fixed column span
// always 6/12
// Responsive spans
// 'auto' — shrinks to content width
// 'grow' — fills remaining space (equivalent to old xs="true")
```
### Spacing and column/row gap
```tsx
// Uniform spacing
// Separate column and row spacing
// Responsive spacing
```
### Offset
```tsx
// Offset pushes the item right by n columns
Centered 4-column block
// Responsive offset
Centered on desktop, left-aligned on mobile
```
### Nested grid
```tsx
{/* Nested grid — no additional container needed in v2 */}
Nested A
Nested B
Sidebar
```
---
## Stack
`Stack` is a one-dimensional layout component (flexbox row or column). Simpler than Grid
for linear sequences of components.
### Basic usage
```tsx
import Stack from '@mui/material/Stack';
import Divider from '@mui/material/Divider';
// Vertical stack (default direction)
// Horizontal row
{user.name}
```
### Responsive direction
```tsx
```
### Divider between items
```tsx
}
>
Section A
Section B
Section C
```
### useFlexGap
By default Stack uses negative margin to simulate gaps. Set `useFlexGap` to use the CSS
`gap` property instead — required when children have `overflow: hidden` or when the
container has `overflow: hidden`.
```tsx
{tags.map((tag) => )}
```
---
## Container
Centers content horizontally with a max-width. The main layout wrapper for page content.
```tsx
import Container from '@mui/material/Container';
// Responsive max-width (uses theme breakpoints)
{/* lg = 1200px by default */}
Page title
// Exact pixel constraint
{/* sm = 600px */}
// Disable max-width (full fluid width)
// 'fixed' — jumps between fixed widths at each breakpoint
// Typical page layout
{/* ... */}
{children}
{/* footer content */}
```
---
## Box as a Layout Primitive
`Box` renders a `div` by default but accepts a `component` prop. It has full access to
the `sx` prop and system shorthands.
```tsx
import Box from '@mui/material/Box';
// Flex centering helper
// Section spacing
{children}
// Scroll container
{longList}
```
---
## Breakpoints
MUI's default breakpoints (in `px`):
| Key | Min width |
|-----|-----------|
| xs | 0 |
| sm | 600 |
| md | 900 |
| lg | 1200 |
| xl | 1536 |
### useMediaQuery
```tsx
import useMediaQuery from '@mui/material/useMediaQuery';
import { useTheme } from '@mui/material/styles';
function ResponsiveComponent() {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
const isTablet = useMediaQuery(theme.breakpoints.between('sm', 'md'));
const isDesktop = useMediaQuery(theme.breakpoints.up('md'));
// SSR: default to a value so the first render matches server output
const prefersDark = useMediaQuery('(prefers-color-scheme: dark)', {
defaultMatches: false,
noSsr: true,
});
return isMobile ? : ;
}
```
### Breakpoint helpers
```tsx
// theme.breakpoints.up(key) — key and above
// theme.breakpoints.down(key) — below key (exclusive)
// theme.breakpoints.between(start, end) — start to end (exclusive end)
// theme.breakpoints.only(key) — exactly key
// In sx prop (shorthand)
Desktop only content
// In styled()
const HiddenOnMobile = styled(Box)(({ theme }) => ({
[theme.breakpoints.down('md')]: {
display: 'none',
},
}));
```
---
## Common Layout Patterns
### App shell: sidebar + main content
```tsx
const DRAWER_WIDTH = 240;
function AppShell() {
const [mobileOpen, setMobileOpen] = React.useState(false);
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
const drawerContent = (
);
return (
t.zIndex.drawer + 1 }}
>
{isMobile && (
setMobileOpen(true)}>
)}
My App
{/* Mobile: temporary drawer */}
setMobileOpen(false)}
ModalProps={{ keepMounted: true }}
sx={{
display: { xs: 'block', md: 'none' },
'& .MuiDrawer-paper': { width: DRAWER_WIDTH },
}}
>
{drawerContent}
{/* Desktop: permanent drawer */}
{drawerContent}
{/* Spacer for AppBar */}
{/* Page content */}
);
}
```
### Dashboard card grid
```tsx
function Dashboard() {
return (
{/* Stat cards row */}
{stats.map((stat) => (
))}
{/* Main content + sidebar */}
Recent Activity
Quick Stats
Top Items
);
}
```
### Centered auth form
```tsx
function LoginPage() {
return (
Sign in
);
}
```
### Masonry layout
```tsx
// For masonry layout, use Masonry from @mui/lab
import Masonry from '@mui/lab/Masonry';
{items.map((item) => (
{item.content}
))}
```
---
## Advanced Layout Patterns
### Responsive AppBar + Drawer Layout
```tsx
import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar';
import Drawer from '@mui/material/Drawer';
import useMediaQuery from '@mui/material/useMediaQuery';
import { useTheme } from '@mui/material/styles';
const DRAWER_WIDTH = 240;
function ResponsiveLayout({ children }: { children: React.ReactNode }) {
const theme = useTheme();
const isDesktop = useMediaQuery(theme.breakpoints.up('md'));
const [mobileOpen, setMobileOpen] = useState(false);
const drawerContent = (
{/* spacer for AppBar height */}
{navItems.map((item) => (
{item.icon}
))}
);
return (
theme.zIndex.drawer + 1 }}>
{!isDesktop && (
setMobileOpen(true)} aria-label="menu">
)}
App
{/* Mobile: temporary drawer */}
{!isDesktop && (
setMobileOpen(false)}
ModalProps={{ keepMounted: true }}
sx={{ '& .MuiDrawer-paper': { width: DRAWER_WIDTH } }}
>
{drawerContent}
)}
{/* Desktop: permanent drawer */}
{isDesktop && (
{drawerContent}
)}
{/* spacer */}
{children}
);
}
```
### Mini Variant Drawer (Icon-Only Collapsed)
```tsx
const MINI_WIDTH = 56;
const FULL_WIDTH = 240;
theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
'& .MuiDrawer-paper': {
width: expanded ? FULL_WIDTH : MINI_WIDTH,
overflowX: 'hidden',
transition: 'inherit',
},
}}
>
setExpanded(!expanded)}>
{expanded ? : }
{navItems.map((item) => (
{item.icon}
{expanded && }
))}
```
### Sticky Header + Scrollable Content
```tsx
App
{/* Scrollable content area */}
{children}
{/* Sticky footer */}
```
### Dashboard Grid Layout
```tsx
{/* Full-width stats row */}
{stats.map((stat) => (
{stat.label}
{stat.value}
))}
{/* Main chart + sidebar */}
{/* Full-width data table */}
```