Mastering MUI Paper Component: Building Styled Information Blocks in React
As a React developer, I've spent countless hours crafting user interfaces that need to stand out visually while maintaining excellent usability. When working with Material UI (MUI), one of the most versatile components I've come to rely on is the Paper component. It's deceptively simple but incredibly powerful for creating elevated surfaces that organize content into distinct, visually appealing blocks.
In this comprehensive guide, I'll walk you through everything you need to know about MUI's Paper component - from basic implementation to advanced customization techniques. By the end, you'll be able to leverage Paper to create professional, well-structured information blocks that enhance your React applications.
What You'll Learn
By the end of this article, you will:
- Understand the core purpose and functionality of MUI's Paper component
- Master the complete API including all props, variants, and configuration options
- Learn how to create common UI patterns using Paper (cards, panels, dialogs)
- Implement custom styling through MUI's theming system and the sx prop
- Build responsive and accessible information blocks
- Combine Paper with other MUI components for complex layouts
- Troubleshoot common issues and implement best practices
Understanding the MUI Paper Component
The Paper component is one of MUI's fundamental building blocks. It's designed based on the material design concept of "paper" - a physical surface that can hold text, images, and actions. In the digital world, Paper serves as a container that creates depth through subtle shadows and a clean background.
At its core, Paper is essentially a div with added styling that provides elevation (shadow), a background color, and rounded corners. This makes it perfect for creating cards, dialogs, menus, and other standalone content blocks that need visual separation from their surroundings.
The beauty of Paper lies in its simplicity and flexibility. It doesn't impose any layout constraints on its children, allowing you to structure your content however you see fit while providing a consistent visual treatment.
Key Features of MUI Paper
Paper offers several key features that make it an essential component in your MUI toolkit:
-
Elevation: Paper can be elevated at different levels (0-24), creating varying degrees of shadow depth to establish visual hierarchy.
-
Square Option: By default, Paper has rounded corners, but you can make it completely square when needed.
-
Variant Control: Paper supports 'elevation' and 'outlined' variants, giving you options for different visual styles.
-
Full Customization: Through MUI's theming system and the sx prop, you can customize every aspect of Paper's appearance.
-
Semantic Flexibility: Paper accepts a component prop, allowing you to change the underlying HTML element (div by default) to maintain semantic correctness.
Paper Component API Deep Dive
Let's examine the complete API for the Paper component to understand all available options.
Core Props
Here's a comprehensive table of the most important props available on the Paper component:
Prop | Type | Default | Description |
---|---|---|---|
children | node | - | The content of the component. |
classes | object | - | Override or extend the styles applied to the component. |
component | elementType | 'div' | The component used for the root node. Either a string to use an HTML element or a component. |
elevation | number | 1 | Shadow depth, corresponds to dp in the spec. It accepts values between 0 and 24 inclusive. |
square | bool | false | If true, rounded corners are disabled. |
sx | object | - | The system prop that allows defining system overrides as well as additional CSS styles. |
variant | 'elevation' | 'outlined' | 'elevation' | The variant to use. |
CSS Classes
The Paper component generates several CSS classes that you can target for customization:
Rule Name | Global Class | Description |
---|---|---|
root | .MuiPaper-root | Styles applied to the root element. |
rounded | .MuiPaper-rounded | Styles applied to the root element if square is false. |
outlined | .MuiPaper-outlined | Styles applied to the root element if variant="outlined" . |
elevation | .MuiPaper-elevation-24 | Styles applied to the root element if |
Understanding Variants
The Paper component offers two main variants:
-
Elevation (Default): Creates a paper surface with a shadow to indicate elevation from the page. The shadow's intensity depends on the
elevation
prop (0-24). -
Outlined: Creates a paper surface with a 1px border instead of a shadow. This is useful when you want a subtle container without the shadow effect.
Each variant serves different design needs. Elevation is ideal when you want to create a sense of depth and hierarchy, while outlined works well for more subtle containers that need to be visually separated without appearing to float above the surface.
Getting Started with Paper: Basic Implementation
Let's start with the basics of using the Paper component in your React application. First, you'll need to install Material UI if you haven't already.
npm install @mui/material @emotion/react @emotion/styled
Or using yarn:
yarn add @mui/material @emotion/react @emotion/styled
Now, let's create a simple Paper component:
import React from 'react';
import { Paper, Typography } from '@mui/material';
function BasicPaper() {
return (
<Paper elevation={3} sx={{ p: 2, maxWidth: 400 }}>
<Typography variant="h5" component="h2">
Basic Paper Component
</Typography>
<Typography variant="body1" sx={{ mt: 1 }}>
This is a simple Paper component with elevation 3. It creates a subtle
shadow to lift the content from the background.
</Typography>
</Paper>
);
}
export default BasicPaper;
In this example, I've created a basic Paper component with:
- An elevation of 3, which gives a moderate shadow effect
- Internal padding of 2 units (16px by default)
- A maximum width of 400px
- Typography components for structured content
The result is a clean, elevated surface that visually separates the content from the rest of the page. This is the fundamental usage of Paper - creating a distinct surface for related content.
Creating Common UI Patterns with Paper
Now that we understand the basics, let's explore how to use Paper to create common UI patterns. I'll show you how to build cards, panels, and other information blocks that you'll frequently need in real-world applications.
Building a Simple Card
Cards are one of the most common uses for the Paper component. Here's how to create a basic card with an image, title, description, and actions:
import React from 'react';
import {
Paper,
Typography,
Button,
Box,
Divider
} from '@mui/material';
function SimpleCard() {
return (
<Paper
elevation={2}
sx={{
maxWidth: 345,
borderRadius: 2,
overflow: 'hidden' // Ensures the image doesn't overflow rounded corners
}} >
{/* Card Media */}
<Box
sx={{
height: 140,
backgroundImage: 'url(https://source.unsplash.com/random/345x140/?nature)',
backgroundSize: 'cover',
backgroundPosition: 'center'
}}
/>
{/* Card Content */}
<Box sx={{ p: 2 }}>
<Typography gutterBottom variant="h5" component="div">
Card Title
</Typography>
<Typography variant="body2" color="text.secondary">
This card is built using MUI's Paper component as the container.
It demonstrates how to create a common card pattern with image,
text content, and action buttons.
</Typography>
</Box>
<Divider />
{/* Card Actions */}
<Box sx={{ display: 'flex', justifyContent: 'flex-end', p: 1.5 }}>
<Button size="small" color="primary" sx={{ mr: 1 }}>
Share
</Button>
<Button size="small" color="primary">
Learn More
</Button>
</Box>
</Paper>
);
}
export default SimpleCard;
This card example demonstrates several important techniques:
- Using a higher border radius (borderRadius: 2) for a more modern card look
- Setting overflow to 'hidden' to ensure the image respects the rounded corners
- Using Box components to create distinct sections within the Paper
- Adding a Divider to separate content from actions
- Structuring the action buttons with flex layout
Creating a Dashboard Panel
Another common use for Paper is creating dashboard panels or information sections. Here's how to build a statistics panel:
import React from 'react';
import {
Paper,
Typography,
Box,
Chip,
LinearProgress
} from '@mui/material';
import TrendingUpIcon from '@mui/icons-material/TrendingUp';
function StatisticsPanel() {
return (
<Paper
elevation={1}
sx={{
p: 3,
borderRadius: 2,
maxWidth: 400,
bgcolor: (theme) => theme.palette.mode === 'dark' ? 'grey.800' : 'grey.50'
}} >
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
<Typography variant="h6" component="h2" fontWeight="medium">
Weekly Performance
</Typography>
<Chip
icon={<TrendingUpIcon />}
label="+12.3%"
size="small"
color="success"
variant="outlined"
/>
</Box>
<Typography variant="h3" component="div" sx={{ mb: 1 }}>
$12,875
</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
Total revenue this week
</Typography>
<LinearProgress
variant="determinate"
value={68}
sx={{ height: 8, borderRadius: 4, mb: 1 }}
/>
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
<Typography variant="body2" color="text.secondary">
Target: $18,000
</Typography>
<Typography variant="body2" fontWeight="medium">
68%
</Typography>
</Box>
</Paper>
);
}
export default StatisticsPanel;
This statistics panel demonstrates:
- Using a subtle background color that adapts to light/dark mode
- Combining multiple elements (Typography, Chip, LinearProgress) within a Paper
- Creating a visual hierarchy with different typography variants
- Using the sx prop for detailed layout adjustments
- Implementing a responsive design that works well at different sizes
Building a Settings Panel
Paper components are also excellent for settings or configuration panels. Here's how to create one:
import React, { useState } from 'react';
import {
Paper,
Typography,
Box,
Switch,
FormControlLabel,
Divider,
Slider,
Select,
MenuItem,
InputLabel,
FormControl
} from '@mui/material';
function SettingsPanel() {
const [notifications, setNotifications] = useState(true);
const [volume, setVolume] = useState(70);
const [theme, setTheme] = useState('system');
return (
<Paper
elevation={3}
sx={{
maxWidth: 500,
p: 3,
borderRadius: 2
}} >
<Typography variant="h5" component="h2" sx={{ mb: 3 }}>
Application Settings
</Typography>
{/* Notifications Setting */}
<Box sx={{ mb: 3 }}>
<FormControlLabel
control={
<Switch
checked={notifications}
onChange={(e) => setNotifications(e.target.checked)}
color="primary"
/>
}
label="Enable notifications"
/>
<Typography variant="body2" color="text.secondary" sx={{ mt: 0.5 }}>
Receive alerts and updates about your account activity
</Typography>
</Box>
<Divider sx={{ my: 3 }} />
{/* Volume Setting */}
<Box sx={{ mb: 3 }}>
<Typography variant="subtitle1" gutterBottom>
Alert Volume
</Typography>
<Slider
value={volume}
onChange={(e, newValue) => setVolume(newValue)}
aria-labelledby="volume-slider"
valueLabelDisplay="auto"
step={10}
marks
min={0}
max={100}
sx={{ maxWidth: 400 }}
/>
</Box>
<Divider sx={{ my: 3 }} />
{/* Theme Setting */}
<Box>
<FormControl variant="outlined" size="small" sx={{ minWidth: 200 }}>
<InputLabel id="theme-select-label">Theme</InputLabel>
<Select
labelId="theme-select-label"
id="theme-select"
value={theme}
onChange={(e) => setTheme(e.target.value)}
label="Theme"
>
<MenuItem value="light">Light</MenuItem>
<MenuItem value="dark">Dark</MenuItem>
<MenuItem value="system">System Default</MenuItem>
</Select>
</FormControl>
<Typography variant="body2" color="text.secondary" sx={{ mt: 1 }}>
Select your preferred color theme
</Typography>
</Box>
</Paper>
);
}
export default SettingsPanel;
This settings panel shows:
- How to organize different types of settings within a single Paper
- Using Divider components to separate logical sections
- Incorporating form controls like Switch, Slider, and Select
- Adding descriptive text to explain each setting
- Managing state for interactive elements
Advanced Customization Techniques
Now that we've covered the basics and common patterns, let's dive into advanced customization techniques for the Paper component.
Styling with the sx Prop
The sx prop is the most direct way to style MUI components. It provides access to the theme and supports a wide range of CSS properties:
import React from 'react';
import { Paper, Typography } from '@mui/material';
function CustomStyledPaper() {
return (
<Paper
elevation={0}
sx={{
p: 3,
borderRadius: 4,
background: 'linear-gradient(145deg, #f5f7fa 0%, #c3cfe2 100%)',
boxShadow: '0px 10px 30px rgba(0, 0, 0, 0.1)',
border: '1px solid rgba(255, 255, 255, 0.3)',
transition: 'transform 0.3s ease, box-shadow 0.3s ease',
'&:hover': {
transform: 'translateY(-5px)',
boxShadow: '0px 15px 35px rgba(0, 0, 0, 0.15)',
},
maxWidth: 400
}} >
<Typography variant="h5" component="h2" sx={{ mb: 2, fontWeight: 600 }}>
Advanced Styled Paper
</Typography>
<Typography variant="body1">
This Paper component uses advanced styling with the sx prop,
including gradients, custom shadows, and hover animations.
</Typography>
</Paper>
);
}
export default CustomStyledPaper;
This example demonstrates several advanced styling techniques:
- Using a linear gradient background instead of a solid color
- Creating a custom box shadow for a more refined look
- Adding a subtle border with transparency
- Implementing hover animations with transform and shadow changes
- Using theme-based spacing (p: 3) alongside direct CSS properties
Theming the Paper Component
For application-wide customization, you can modify the Paper component through MUI's theming system:
import React from 'react';
import {
ThemeProvider,
createTheme,
Paper,
Typography,
Box,
CssBaseline
} from '@mui/material';
// Create a custom theme
const theme = createTheme({
palette: {
primary: {
main: '#3f51b5',
},
secondary: {
main: '#f50057',
},
},
components: {
// Customize the Paper component globally
MuiPaper: {
styleOverrides: {
// Apply styles to the root of all Paper components
root: {
borderRadius: 12,
padding: 16,
},
// Apply styles to the outlined variant
outlined: {
borderColor: '#3f51b5',
borderWidth: 2,
},
// Apply styles to specific elevation levels
elevation1: {
boxShadow: '0px 3px 15px rgba(0,0,0,0.05)',
},
elevation3: {
boxShadow: '0px 6px 25px rgba(0,0,0,0.08)',
},
},
// Add default props for all Paper components
defaultProps: {
elevation: 3,
},
},
},
});
function ThemedPaperExample() {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Box sx={{ display: 'flex', gap: 3, flexWrap: 'wrap' }}>
{/* This Paper will use the global theme settings */}
<Paper>
<Typography variant="h6">Default Themed Paper</Typography>
<Typography variant="body2" sx={{ mt: 1 }}>
This Paper uses the global theme settings with elevation 3.
</Typography>
</Paper>
{/* This Paper will use the outlined variant with themed styles */}
<Paper variant="outlined">
<Typography variant="h6">Outlined Themed Paper</Typography>
<Typography variant="body2" sx={{ mt: 1 }}>
This Paper uses the themed outlined variant with custom border.
</Typography>
</Paper>
{/* This Paper overrides some theme settings */}
<Paper elevation={1} sx={{ bgcolor: 'secondary.light' }}>
<Typography variant="h6">Custom Themed Paper</Typography>
<Typography variant="body2" sx={{ mt: 1 }}>
This Paper uses elevation 1 with a custom background color.
</Typography>
</Paper>
</Box>
</ThemeProvider>
);
}
export default ThemedPaperExample;
This theming example shows:
- How to create a custom theme with createTheme
- Customizing the Paper component globally through styleOverrides
- Setting default props for all Paper components
- Targeting specific variants like 'outlined'
- Customizing specific elevation levels
- Overriding theme settings for individual Paper instances
Creating Custom Paper Variants
You can extend MUI's theming system to create your own Paper variants:
import React from 'react';
import {
ThemeProvider,
createTheme,
Paper,
Typography,
Box,
styled,
CssBaseline
} from '@mui/material';
// Extend the theme to include custom variants
const theme = createTheme({
components: {
MuiPaper: {
variants: [
{
props: { variant: 'glass' },
style: {
background: 'rgba(255, 255, 255, 0.7)',
backdropFilter: 'blur(10px)',
border: '1px solid rgba(255, 255, 255, 0.3)',
boxShadow: '0 4px 30px rgba(0, 0, 0, 0.1)',
},
},
{
props: { variant: 'dashboard' },
style: {
borderRadius: 16,
padding: 24,
boxShadow: '0px 8px 30px rgba(0, 0, 0, 0.12)',
border: '1px solid #f0f0f0',
},
},
],
},
},
});
// Create a styled version of Paper for a custom card
const CardPaper = styled(Paper)(({ theme }) => ({
borderRadius: 12,
padding: 0,
overflow: 'hidden',
transition: 'transform 0.2s ease-in-out',
'&:hover': {
transform: 'scale(1.02)',
},
}));
function CustomPaperVariants() {
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Box
sx={{
display: 'flex',
gap: 3,
flexWrap: 'wrap',
p: 3,
backgroundImage: 'url(https://source.unsplash.com/random/1600x900/?landscape)',
backgroundSize: 'cover',
minHeight: '100vh'
}} >
{/* Glass morphism variant */}
<Paper variant="glass" sx={{ p: 3, maxWidth: 350 }}>
<Typography variant="h6">Glass Morphism Paper</Typography>
<Typography variant="body2" sx={{ mt: 1 }}>
This Paper uses a custom glass morphism effect with backdrop filter
blur and transparency.
</Typography>
</Paper>
{/* Dashboard panel variant */}
<Paper variant="dashboard" sx={{ maxWidth: 350 }}>
<Typography variant="h6">Dashboard Panel</Typography>
<Typography variant="body2" sx={{ mt: 1 }}>
This Paper uses a custom dashboard panel style with larger border
radius and specific shadow.
</Typography>
</Paper>
{/* Styled card variant */}
<CardPaper elevation={2} sx={{ maxWidth: 350 }}>
<Box sx={{
height: 150,
bgcolor: 'primary.main',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
<Typography variant="h5" color="white">Card Header</Typography>
</Box>
<Box sx={{ p: 3 }}>
<Typography variant="body1">
This Paper uses the styled API to create a custom card component
with hover effects.
</Typography>
</Box>
</CardPaper>
</Box>
</ThemeProvider>
);
}
export default CustomPaperVariants;
This example demonstrates:
- Creating custom variants through the theme.components.MuiPaper.variants configuration
- Implementing a glass morphism effect using backdrop-filter and rgba colors
- Creating a dashboard-specific Paper variant with custom styling
- Using the styled API to create a specialized Paper component
- Adding interactive effects like hover scaling
Building Responsive Paper Layouts
Creating responsive layouts with Paper components is essential for modern web applications. Let's explore how to build information blocks that adapt to different screen sizes.
Responsive Grid of Paper Cards
import React from 'react';
import {
Paper,
Typography,
Grid,
Box,
useTheme,
useMediaQuery
} from '@mui/material';
// Sample data for our cards
const infoBlocks = [
{
title: "Getting Started",
description: "Learn the basics of our platform and how to set up your account.",
icon: "🚀"
},
{
title: "Features Overview",
description: "Explore the key features that make our product stand out.",
icon: "✨"
},
{
title: "Best Practices",
description: "Tips and tricks to get the most out of our platform.",
icon: "📝"
},
{
title: "API Documentation",
description: "Technical details for developers integrating with our system.",
icon: "🔧"
}
];
function ResponsivePaperGrid() {
const theme = useTheme();
const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
return (
<Box sx={{ flexGrow: 1, p: 3 }}>
<Grid container spacing={3}>
{infoBlocks.map((block, index) => (
<Grid item xs={12} sm={6} md={3} key={index}>
<Paper
elevation={2}
sx={{
p: 3,
height: '100%',
display: 'flex',
flexDirection: 'column',
borderRadius: 2,
transition: 'transform 0.2s, box-shadow 0.2s',
'&:hover': {
transform: isSmallScreen ? 'none' : 'translateY(-4px)',
boxShadow: isSmallScreen ? 2 : 4
}
}} >
<Box
sx={{
fontSize: '2.5rem',
mb: 2,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: 80
}} >
{block.icon}
</Box>
<Typography variant="h6" component="h2" gutterBottom align="center">
{block.title}
</Typography>
<Typography variant="body2" color="text.secondary" align="center">
{block.description}
</Typography>
</Paper>
</Grid>
))}
</Grid>
</Box>
);
}
export default ResponsivePaperGrid;
This responsive grid example demonstrates:
- Using MUI's Grid system to create a responsive layout
- Adapting the number of columns based on screen size (xs, sm, md breakpoints)
- Using useMediaQuery to conditionally apply hover effects only on larger screens
- Setting height: '100%' to ensure all Paper components in a row have the same height
- Creating a consistent card design with centered content
Responsive Dashboard Layout
Let's create a more complex responsive dashboard layout with Paper components:
import React from 'react';
import {
Paper,
Typography,
Grid,
Box,
Divider,
List,
ListItem,
ListItemText,
ListItemIcon,
LinearProgress,
useTheme,
useMediaQuery
} from '@mui/material';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import ErrorIcon from '@mui/icons-material/Error';
import WarningIcon from '@mui/icons-material/Warning';
function ResponsiveDashboard() {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
return (
<Box sx={{ flexGrow: 1, p: 3 }}>
<Grid container spacing={3}>
{/* Main stats row */}
<Grid item xs={12}>
<Grid container spacing={3}>
{/* Stat card 1 */}
<Grid item xs={12} sm={6} md={3}>
<Paper
elevation={2}
sx={{
p: 3,
textAlign: 'center',
height: '100%',
borderRadius: 2
}} >
<Typography variant="h3" component="div" color="primary">
87%
</Typography>
<Typography variant="subtitle1">System Uptime</Typography>
</Paper>
</Grid>
{/* Stat card 2 */}
<Grid item xs={12} sm={6} md={3}>
<Paper
elevation={2}
sx={{
p: 3,
textAlign: 'center',
height: '100%',
borderRadius: 2
}}
>
<Typography variant="h3" component="div" color="success.main">
142
</Typography>
<Typography variant="subtitle1">Active Users</Typography>
</Paper>
</Grid>
{/* Stat card 3 */}
<Grid item xs={12} sm={6} md={3}>
<Paper
elevation={2}
sx={{
p: 3,
textAlign: 'center',
height: '100%',
borderRadius: 2
}}
>
<Typography variant="h3" component="div" color="warning.main">
8
</Typography>
<Typography variant="subtitle1">Pending Tasks</Typography>
</Paper>
</Grid>
{/* Stat card 4 */}
<Grid item xs={12} sm={6} md={3}>
<Paper
elevation={2}
sx={{
p: 3,
textAlign: 'center',
height: '100%',
borderRadius: 2
}}
>
<Typography variant="h3" component="div" color="error.main">
3
</Typography>
<Typography variant="subtitle1">Critical Issues</Typography>
</Paper>
</Grid>
</Grid>
</Grid>
{/* Main content area */}
<Grid item xs={12} md={8}>
<Paper
elevation={2}
sx={{
p: 3,
height: '100%',
borderRadius: 2
}}
>
<Typography variant="h6" gutterBottom>
System Performance
</Typography>
<Divider sx={{ mb: 2 }} />
<Box sx={{ mb: 4 }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
<Typography variant="body2">CPU Usage</Typography>
<Typography variant="body2" fontWeight="medium">
67%
</Typography>
</Box>
<LinearProgress
variant="determinate"
value={67}
color="primary"
sx={{ height: 8, borderRadius: 4 }}
/>
</Box>
<Box sx={{ mb: 4 }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
<Typography variant="body2">Memory Usage</Typography>
<Typography variant="body2" fontWeight="medium">
45%
</Typography>
</Box>
<LinearProgress
variant="determinate"
value={45}
color="secondary"
sx={{ height: 8, borderRadius: 4 }}
/>
</Box>
<Box>
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
<Typography variant="body2">Disk Space</Typography>
<Typography variant="body2" fontWeight="medium">
82%
</Typography>
</Box>
<LinearProgress
variant="determinate"
value={82}
color="warning"
sx={{ height: 8, borderRadius: 4 }}
/>
</Box>
</Paper>
</Grid>
{/* Sidebar */}
<Grid item xs={12} md={4}>
<Paper
elevation={2}
sx={{
p: 3,
height: '100%',
borderRadius: 2
}}
>
<Typography variant="h6" gutterBottom>
Recent Alerts
</Typography>
<Divider sx={{ mb: 2 }} />
<List sx={{ p: 0 }}>
<ListItem disableGutters>
<ListItemIcon sx={{ minWidth: 40 }}>
<ErrorIcon color="error" />
</ListItemIcon>
<ListItemText
primary="Database Connection Error"
secondary="10 minutes ago"
primaryTypographyProps={{
variant: isMobile ? 'body2' : 'body1',
fontWeight: 'medium'
}}
secondaryTypographyProps={{
variant: isMobile ? 'caption' : 'body2'
}}
/>
</ListItem>
<ListItem disableGutters>
<ListItemIcon sx={{ minWidth: 40 }}>
<WarningIcon color="warning" />
</ListItemIcon>
<ListItemText
primary="High CPU Usage Detected"
secondary="25 minutes ago"
primaryTypographyProps={{
variant: isMobile ? 'body2' : 'body1',
fontWeight: 'medium'
}}
secondaryTypographyProps={{
variant: isMobile ? 'caption' : 'body2'
}}
/>
</ListItem>
<ListItem disableGutters>
<ListItemIcon sx={{ minWidth: 40 }}>
<CheckCircleIcon color="success" />
</ListItemIcon>
<ListItemText
primary="Backup Completed Successfully"
secondary="1 hour ago"
primaryTypographyProps={{
variant: isMobile ? 'body2' : 'body1',
fontWeight: 'medium'
}}
secondaryTypographyProps={{
variant: isMobile ? 'caption' : 'body2'
}}
/>
</ListItem>
</List>
</Paper>
</Grid>
</Grid>
</Box>
);
}
export default ResponsiveDashboard;
This dashboard layout demonstrates:
- Creating a complex, multi-section layout with Paper components
- Using nested Grid containers for better organization
- Adapting typography size based on screen size using useMediaQuery
- Maintaining consistent spacing and elevation across all Paper components
- Using different MUI components within Paper (LinearProgress, List, etc.)
- Implementing a responsive sidebar that moves below the main content on mobile
Accessibility Considerations for Paper Components
When using Paper components, it's important to ensure they're accessible to all users. Here are some best practices:
import React from 'react';
import { Paper, Typography, Button, Box } from '@mui/material';
function AccessiblePaper() {
return (
<Paper
elevation={3}
sx={{ p: 3, maxWidth: 500, borderRadius: 2 }}
// Add role to improve semantic meaning when appropriate
role="region"
// Add aria-label for screen readers
aria-label="Important notification"
// Ensure sufficient color contrast
style={{ backgroundColor: '#f5f5f5', color: '#333333' }} >
<Typography
variant="h5"
component="h2"
gutterBottom
// Use tabIndex only if this heading needs to be focusable
tabIndex={0} >
Accessibility Matters
</Typography>
<Typography variant="body1" paragraph>
This Paper component follows accessibility best practices with proper
contrast ratios, semantic HTML, and ARIA attributes where needed.
</Typography>
<Box sx={{ display: 'flex', gap: 2 }}>
<Button
variant="contained"
color="primary"
// Add descriptive aria-label when button text isn't clear
aria-label="Learn more about accessibility"
>
Learn More
</Button>
<Button
variant="outlined"
// Ensure keyboard navigation works properly
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
console.log('Dismiss button activated via keyboard');
}
}}
>
Dismiss
</Button>
</Box>
</Paper>
);
}
export default AccessiblePaper;
Key accessibility considerations demonstrated:
- Adding appropriate ARIA roles and labels to improve screen reader experience
- Ensuring sufficient color contrast between text and background
- Making interactive elements keyboard accessible
- Using semantic HTML structure with proper heading levels
- Adding descriptive labels for interactive elements
Performance Optimization
When working with many Paper components, especially in large lists or grids, performance can become a concern. Here are some optimization techniques:
import React, { useState, useMemo } from 'react';
import { Paper, Typography, Box, List, ListItem, Divider } from '@mui/material';
import { FixedSizeList } from 'react-window';
// Sample data - imagine this is a large dataset
const generateItems = (count) => {
return Array(count)
.fill(null)
.map((_, i) => ({
id: i,
title: `Item ${i + 1}`,
description: `This is the description for item ${i + 1}. It contains some details about this particular item.`
}));
};
// A virtualized list of Paper components for better performance
function OptimizedPaperList() {
const [items] = useState(() => generateItems(1000));
// Memoize the rendering function to prevent recreating it on each render
const renderRow = useMemo(() => {
return ({ index, style }) => {
const item = items[index];
return (
<div style={style}>
<Paper
elevation={1}
sx={{
p: 2,
m: 1,
borderRadius: 2,
// Using sx prop efficiently by avoiding deep nesting
// which would create new object on each render
display: 'flex',
flexDirection: 'column'
}} >
<Typography variant="subtitle1">{item.title}</Typography>
<Typography variant="body2" color="text.secondary">
{item.description}
</Typography>
</Paper>
</div>
);
};
}, [items]);
return (
<Box sx={{ height: 400, width: '100%', maxWidth: 600 }}>
<Typography variant="h6" gutterBottom>
Optimized List with 1,000 Paper Components
</Typography>
<Paper
elevation={3}
sx={{
height: '100%',
borderRadius: 2,
// Use simple values in sx prop when possible
overflow: 'hidden'
}}
>
<FixedSizeList
height={400}
width="100%"
itemSize={100}
itemCount={items.length}
overscanCount={5}
>
{renderRow}
</FixedSizeList>
</Paper>
</Box>
);
}
// Regular Paper component optimized for performance
function OptimizedPaper() {
return (
<Box sx={{ display: 'flex', gap: 3, flexWrap: 'wrap' }}>
<Paper
// Use elevation={0} when shadow isn't needed
elevation={0}
// Apply border directly instead of using variant="outlined"
// to avoid extra theme calculations
sx={{
p: 3,
border: '1px solid #e0e0e0',
maxWidth: 350
}} >
<Typography variant="h6">Performance Optimized Paper</Typography>
<Typography variant="body2">
This Paper uses direct styles instead of variants for better performance.
</Typography>
</Paper>
<OptimizedPaperList />
</Box>
);
}
export default OptimizedPaper;
This example demonstrates several performance optimization techniques:
- Using virtualization with react-window to render only visible Paper components
- Memoizing render functions to prevent unnecessary recreations
- Keeping sx prop objects simple to minimize object creation
- Using elevation=0 when shadows aren't needed
- Using direct styles instead of variants when appropriate
- Applying fixed dimensions to avoid layout recalculations
Common Issues and Solutions
Let's address some common issues developers face when working with Paper components and their solutions:
Issue 1: Content Overflow in Paper Components
import React from 'react';
import { Paper, Typography, Box } from '@mui/material';
function OverflowSolution() {
return (
<Box sx={{ display: 'flex', gap: 3, flexWrap: 'wrap' }}>
{/* Problem: Content overflows the Paper */}
<Paper
elevation={2}
sx={{
p: 2,
maxWidth: 250,
borderRadius: 2,
border: '1px solid red' // To highlight the issue
}} >
<Typography variant="h6">Overflow Problem</Typography>
<Typography variant="body2">
This Paper has content that might overflow because it contains a very long word:
supercalifragilisticexpialidocious or a long URL: https://example.com/very/long/path/that/does/not/break
</Typography>
</Paper>
{/* Solution: Add overflow handling */}
<Paper
elevation={2}
sx={{
p: 2,
maxWidth: 250,
borderRadius: 2,
// Solution: Add these properties
overflow: 'hidden',
'& .MuiTypography-root': {
wordWrap: 'break-word',
overflowWrap: 'break-word',
hyphens: 'auto'
}
}}
>
<Typography variant="h6">Overflow Solution</Typography>
<Typography variant="body2">
This Paper handles content overflow properly with long words:
supercalifragilisticexpialidocious or a long URL: https://example.com/very/long/path/that/does/not/break
</Typography>
</Paper>
</Box>
);
}
export default OverflowSolution;
Issue 2: Inconsistent Elevation Appearance
import React from 'react';
import { Paper, Typography, Box, useTheme } from '@mui/material';
function ElevationSolution() {
const theme = useTheme();
return (
<Box sx={{ display: 'flex', gap: 3, flexWrap: 'wrap' }}>
{/* Problem: Elevation looks different on different backgrounds */}
<Box sx={{ p: 3, bgcolor: '#f5f5f5' }}>
<Paper elevation={3} sx={{ p: 2, maxWidth: 250 }}>
<Typography variant="h6">Elevation Issue</Typography>
<Typography variant="body2">
This Paper's elevation looks different on colored backgrounds.
</Typography>
</Paper>
</Box>
{/* Solution: Custom consistent shadow */}
<Box sx={{ p: 3, bgcolor: '#f5f5f5' }}>
<Paper
elevation={0}
sx={{
p: 2,
maxWidth: 250,
boxShadow: theme.shadows[3],
// Add a subtle border for consistent appearance
border: '1px solid rgba(0, 0, 0, 0.08)'
}}
>
<Typography variant="h6">Elevation Solution</Typography>
<Typography variant="body2">
This Paper uses a consistent shadow with a subtle border.
</Typography>
</Paper>
</Box>
</Box>
);
}
export default ElevationSolution;
Issue 3: Responsive Height Matching
import React from 'react';
import { Paper, Typography, Grid, Box } from '@mui/material';
function HeightMatchingSolution() {
return (
<Box sx={{ flexGrow: 1 }}>
<Typography variant="h6" gutterBottom>Problem: Uneven Heights</Typography>
<Grid container spacing={3} sx={{ mb: 4 }}>
<Grid item xs={12} sm={6} md={4}>
<Paper elevation={2} sx={{ p: 2 }}>
<Typography variant="h6">Card 1</Typography>
<Typography variant="body2">Short content.</Typography>
</Paper>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<Paper elevation={2} sx={{ p: 2 }}>
<Typography variant="h6">Card 2</Typography>
<Typography variant="body2">
This card has much more content than the others, causing uneven heights
in the grid layout. This can look unprofessional and create a jagged
visual appearance.
</Typography>
</Paper>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<Paper elevation={2} sx={{ p: 2 }}>
<Typography variant="h6">Card 3</Typography>
<Typography variant="body2">Medium length content here.</Typography>
</Paper>
</Grid>
</Grid>
<Typography variant="h6" gutterBottom>Solution: Matched Heights</Typography>
<Grid container spacing={3}>
<Grid item xs={12} sm={6} md={4}>
<Paper
elevation={2}
sx={{
p: 2,
height: '100%', // Key solution
display: 'flex',
flexDirection: 'column'
}}
>
<Typography variant="h6">Card 1</Typography>
<Typography variant="body2">Short content.</Typography>
</Paper>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<Paper
elevation={2}
sx={{
p: 2,
height: '100%', // Key solution
display: 'flex',
flexDirection: 'column'
}}
>
<Typography variant="h6">Card 2</Typography>
<Typography variant="body2">
This card has much more content than the others, but now the heights
match perfectly because we've set height: '100%' on the Paper and
display: 'flex' with flexDirection: 'column'.
</Typography>
</Paper>
</Grid>
<Grid item xs={12} sm={6} md={4}>
<Paper
elevation={2}
sx={{
p: 2,
height: '100%', // Key solution
display: 'flex',
flexDirection: 'column'
}}
>
<Typography variant="h6">Card 3</Typography>
<Typography variant="body2">Medium length content here.</Typography>
</Paper>
</Grid>
</Grid>
</Box>
);
}
export default HeightMatchingSolution;
Best Practices for Paper Components
Based on my experience, here are some best practices to follow when working with MUI Paper components:
1. Choose the Right Elevation Level
import React from 'react';
import { Paper, Typography, Box } from '@mui/material';
function ElevationBestPractices() {
return (
<Box sx={{ display: 'flex', gap: 3, flexWrap: 'wrap', p: 3, bgcolor: '#f5f5f5' }}>
{/* Primary content - higher elevation */}
<Paper elevation={3} sx={{ p: 3, maxWidth: 350 }}>
<Typography variant="h5" gutterBottom>Primary Content</Typography>
<Typography variant="body1">
Use higher elevation (3-6) for primary content that should stand out.
This creates a clear visual hierarchy and draws the user's attention.
</Typography>
</Paper>
{/* Secondary content - medium elevation */}
<Paper elevation={1} sx={{ p: 3, maxWidth: 350 }}>
<Typography variant="h5" gutterBottom>Secondary Content</Typography>
<Typography variant="body1">
Use lower elevation (1-2) for secondary content that should be visible
but not compete with primary content for attention.
</Typography>
</Paper>
{/* Background content - no elevation */}
<Paper elevation={0} sx={{ p: 3, maxWidth: 350, border: '1px solid #e0e0e0' }}>
<Typography variant="h5" gutterBottom>Background Content</Typography>
<Typography variant="body1">
Use elevation={0} with a subtle border for background content or
when you want to group content without creating visual noise.
</Typography>
</Paper>
</Box>
);
}
export default ElevationBestPractices;
2. Maintain Consistent Styling
import React from 'react';
import { Paper, Typography, Box, ThemeProvider, createTheme } from '@mui/material';
// Create a theme with consistent Paper styling
const theme = createTheme({
components: {
MuiPaper: {
styleOverrides: {
root: {
borderRadius: 8,
},
},
defaultProps: {
elevation: 2,
},
},
},
});
// Create reusable styled Paper components
function InfoCard({ title, children, ...props }) {
return (
<Paper
{...props}
sx={{
p: 3,
// Allow sx prop to extend these base styles
...(props.sx || {})
}} >
{title && (
<Typography variant="h6" gutterBottom>
{title}
</Typography>
)}
{children}
</Paper>
);
}
function ConsistentStylingBestPractices() {
return (
<ThemeProvider theme={theme}>
<Box sx={{ display: 'flex', gap: 3, flexWrap: 'wrap' }}>
<InfoCard title="Consistent Component">
<Typography variant="body1">
Create reusable Paper-based components to ensure consistency
throughout your application.
</Typography>
</InfoCard>
<InfoCard
title="Extended Component"
sx={{ bgcolor: 'primary.light', color: 'primary.contrastText' }}
>
<Typography variant="body1">
Extend your base components when needed while maintaining
the same structure and behavior.
</Typography>
</InfoCard>
<InfoCard variant="outlined" title="Variant Component">
<Typography variant="body1">
Use variants consistently for specific purposes across
your application.
</Typography>
</InfoCard>
</Box>
</ThemeProvider>
);
}
export default ConsistentStylingBestPractices;
3. Optimize for Performance
import React, { memo } from 'react';
import { Paper, Typography, Box } from '@mui/material';
// Memoize components that don't need frequent updates
const StaticPaper = memo(({ title, content }) => (
{" "}
<Paper elevation={1} sx={{ p: 2, maxWidth: 300 }}>
<Typography variant="h6">{title}</Typography>
<Typography variant="body2">{content}</Typography>
</Paper>
));
function PerformanceBestPractices() {
return (
<Box sx={{ display: 'flex', gap: 3, flexWrap: 'wrap' }}>
{/* Use elevation={0} for subtle containers */}
<Paper
elevation={0}
sx={{
p: 3,
border: '1px solid #e0e0e0',
borderRadius: 2,
maxWidth: 350
}} >
<Typography variant="h6">Minimize Elevation</Typography>
<Typography variant="body2">
Use elevation={0} with borders when possible to reduce rendering cost.
Shadows are more expensive to render than borders.
</Typography>
</Paper>
{/* Use memo for static content */}
<StaticPaper
title="Memoize Static Components"
content="Use React.memo for Paper components that don't change frequently to prevent unnecessary re-renders."
/>
{/* Avoid deep nesting */}
<Paper elevation={1} sx={{ p: 2, maxWidth: 350, borderRadius: 2 }}>
<Typography variant="h6">Avoid Deep Nesting</Typography>
<Typography variant="body2" sx={{ mb: 2 }}>
Avoid nesting Paper components within each other when possible.
Instead, use alternative components for inner content:
</Typography>
<Box sx={{ p: 2, bgcolor: 'grey.100', borderRadius: 1 }}>
<Typography variant="body2">
Use Box with bgcolor instead of nested Paper components.
</Typography>
</Box>
</Paper>
</Box>
);
}
export default PerformanceBestPractices;
Wrapping Up
Throughout this guide, we've explored the MUI Paper component in depth - from its basic implementation to advanced customization techniques. Paper is one of those components that seems simple on the surface but offers tremendous flexibility for creating visually appealing and well-structured information blocks in your React applications.
To recap what we've learned:
- Paper provides an elevated surface that creates visual distinction between content blocks
- It offers extensive customization through props like elevation, variant, and square
- You can create complex UI patterns like cards, panels, and dashboards using Paper
- The sx prop and theming system allow for comprehensive styling control
- Accessibility and performance considerations are crucial for production applications
By following the best practices and techniques outlined in this guide, you'll be able to leverage Paper to create professional, consistent, and user-friendly interfaces. Remember that good design is about clarity and purpose - use Paper to guide your users' attention and organize your content in meaningful ways.
Whether you're building a simple information card or a complex dashboard, the Paper component provides the foundation for creating clean, elevated surfaces that enhance your application's visual hierarchy and user experience.