+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Part 168 of 355

📘 Material-UI with TypeScript: Component Library

Master material-ui with typescript: component library in TypeScript with practical examples, best practices, and real-world applications 🚀

🚀Intermediate
25 min read

Prerequisites

  • Basic understanding of JavaScript 📝
  • TypeScript installation ⚡
  • VS Code or preferred IDE 💻

What you'll learn

  • Understand the concept fundamentals 🎯
  • Apply the concept in real projects 🏗️
  • Debug common issues 🐛
  • Write type-safe code ✨

🎯 Introduction

Welcome to this exciting tutorial on Material-UI with TypeScript! 🎉 In this guide, we’ll explore how to harness the power of Material-UI (MUI) with TypeScript to create beautiful, type-safe React applications.

You’ll discover how Material-UI’s component library can transform your TypeScript development experience. Whether you’re building modern dashboards 📊, mobile-first apps 📱, or complex user interfaces 🌐, understanding Material-UI with TypeScript is essential for creating stunning, maintainable applications.

By the end of this tutorial, you’ll feel confident building professional-grade UI components with Material-UI and TypeScript! Let’s dive in! 🏊‍♂️

📚 Understanding Material-UI with TypeScript

🤔 What is Material-UI?

Material-UI is like having a professional designer’s toolkit 🎨 right in your TypeScript project. Think of it as a treasure chest 💎 that contains pre-built, beautiful components that follow Google’s Material Design principles.

In TypeScript terms, Material-UI provides fully typed components with built-in theme support, customization options, and accessibility features ✨. This means you can:

  • ✨ Build beautiful UIs quickly with pre-made components
  • 🚀 Get excellent TypeScript support with full type safety
  • 🛡️ Ensure accessibility compliance out of the box
  • 🎨 Customize themes and styling with type-safe props

💡 Why Use Material-UI with TypeScript?

Here’s why developers love this combination:

  1. Type Safety 🔒: Full TypeScript support for all components and props
  2. Developer Experience 💻: Incredible autocomplete and IntelliSense
  3. Design Consistency 📐: Material Design principles built-in
  4. Rich Component Library 🧱: 80+ components ready to use
  5. Theme System 🎨: Powerful theming with TypeScript support
  6. Community & Support 🤝: Massive ecosystem and documentation

Real-world example: Imagine building an admin dashboard 📊. With Material-UI and TypeScript, you get beautiful data tables, charts, navigation, and forms - all with complete type safety!

🔧 Basic Syntax and Usage

📦 Installation & Setup

Let’s start by setting up Material-UI in a TypeScript project:

# 👋 Install the essentials
npm install @mui/material @emotion/react @emotion/styled
npm install @mui/icons-material  # 🎨 For beautiful icons
npm install @types/react @types/react-dom  # 📝 TypeScript types

📝 Basic Component Example

Let’s create our first Material-UI component:

// 👋 Hello, Material-UI with TypeScript!
import React from 'react';
import { Button, Typography, Box } from '@mui/material';
import { Favorite } from '@mui/icons-material';

// 🎨 Our first typed MUI component
const WelcomeCard: React.FC = () => {
  return (
    <Box sx={{ padding: 3, textAlign: 'center' }}>
      <Typography variant="h4" component="h1" gutterBottom>
        Welcome to MUI! 🎉
      </Typography>
      <Button 
        variant="contained" 
        color="primary"
        startIcon={<Favorite />}
        onClick={() => console.log('MUI is awesome! ❤️')}
      >
        Click Me! ✨
      </Button>
    </Box>
  );
};

💡 Explanation: Notice how TypeScript provides full IntelliSense for all MUI props! The sx prop gives us type-safe styling.

🎯 Theme Setup with TypeScript

Here’s how to set up a custom theme with full type safety:

// 🎨 Create a type-safe theme
import { createTheme, ThemeProvider } from '@mui/material/styles';
import { CssBaseline } from '@mui/material';

// 🌈 Custom theme with TypeScript
const theme = createTheme({
  palette: {
    primary: {
      main: '#1976d2',  // 💙 Beautiful blue
    },
    secondary: {
      main: '#f50057',  // 💖 Pink accent
    },
  },
  typography: {
    h1: {
      fontSize: '2.5rem',  // 📝 Custom typography
      fontWeight: 700,
    },
  },
});

// 🏗️ App wrapper with theme
const App: React.FC = () => {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />  {/* 🧹 CSS reset */}
      <WelcomeCard />
    </ThemeProvider>
  );
};

💡 Practical Examples

🛒 Example 1: E-commerce Product Card

Let’s build a real product card component:

// 🛍️ Product interface with full typing
interface Product {
  id: string;
  name: string;
  price: number;
  image: string;
  rating: number;
  inStock: boolean;
  category: 'electronics' | 'clothing' | 'books' | 'home';
}

// 🎨 Product card component
import React from 'react';
import {
  Card,
  CardMedia,
  CardContent,
  CardActions,
  Typography,
  Button,
  Chip,
  Rating,
  Box
} from '@mui/material';
import { ShoppingCart, Favorite } from '@mui/icons-material';

interface ProductCardProps {
  product: Product;
  onAddToCart: (productId: string) => void;
  onWishlist: (productId: string) => void;
}

const ProductCard: React.FC<ProductCardProps> = ({ 
  product, 
  onAddToCart, 
  onWishlist 
}) => {
  return (
    <Card sx={{ maxWidth: 345, margin: 2 }}>
      {/* 🖼️ Product image */}
      <CardMedia
        component="img"
        height="200"
        image={product.image}
        alt={product.name}
      />
      
      <CardContent>
        {/* 📝 Product details */}
        <Typography variant="h6" component="h2" gutterBottom>
          {product.name} 
        </Typography>
        
        <Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}>
          <Rating value={product.rating} readOnly size="small" />
          <Typography variant="body2" sx={{ ml: 1 }}>
            ({product.rating}/5) ⭐
          </Typography>
        </Box>
        
        {/* 💰 Price */}
        <Typography variant="h5" color="primary" fontWeight="bold">
          ${product.price.toFixed(2)}
        </Typography>
        
        {/* 🏷️ Stock status */}
        <Chip 
          label={product.inStock ? 'In Stock ✅' : 'Out of Stock ❌'}
          color={product.inStock ? 'success' : 'error'}
          size="small"
          sx={{ mt: 1 }}
        />
      </CardContent>
      
      <CardActions>
        {/* 🛒 Action buttons */}
        <Button
          variant="contained"
          startIcon={<ShoppingCart />}
          onClick={() => onAddToCart(product.id)}
          disabled={!product.inStock}
          fullWidth
        >
          Add to Cart
        </Button>
        <Button
          variant="outlined"
          startIcon={<Favorite />}
          onClick={() => onWishlist(product.id)}
        >
          ❤️
        </Button>
      </CardActions>
    </Card>
  );
};

// 🎮 Using our product card
const ProductShowcase: React.FC = () => {
  const sampleProduct: Product = {
    id: 'ts-book-1',
    name: 'TypeScript Mastery Book',
    price: 39.99,
    image: '/images/typescript-book.jpg',
    rating: 4.8,
    inStock: true,
    category: 'books'
  };

  return (
    <ProductCard
      product={sampleProduct}
      onAddToCart={(id) => console.log(`Adding ${id} to cart! 🛒`)}
      onWishlist={(id) => console.log(`Added ${id} to wishlist! ❤️`)}
    />
  );
};

📊 Example 2: Dashboard with Data Table

Let’s create a type-safe data dashboard:

// 📈 User data interface
interface UserData {
  id: string;
  name: string;
  email: string;
  role: 'admin' | 'user' | 'moderator';
  status: 'active' | 'inactive' | 'pending';
  joinDate: Date;
  avatar?: string;
}

// 📊 Dashboard component
import React, { useState } from 'react';
import {
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Paper,
  Avatar,
  Chip,
  IconButton,
  Typography,
  Box,
  TextField,
  InputAdornment
} from '@mui/material';
import { Edit, Delete, Search } from '@mui/icons-material';

interface UserDashboardProps {
  users: UserData[];
  onEdit: (user: UserData) => void;
  onDelete: (userId: string) => void;
}

const UserDashboard: React.FC<UserDashboardProps> = ({ 
  users, 
  onEdit, 
  onDelete 
}) => {
  const [searchTerm, setSearchTerm] = useState<string>('');

  // 🔍 Filter users based on search
  const filteredUsers = users.filter(user =>
    user.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
    user.email.toLowerCase().includes(searchTerm.toLowerCase())
  );

  // 🎨 Get status color
  const getStatusColor = (status: UserData['status']) => {
    switch (status) {
      case 'active': return 'success';
      case 'inactive': return 'error';
      case 'pending': return 'warning';
      default: return 'default';
    }
  };

  return (
    <Box sx={{ p: 3 }}>
      {/* 📝 Dashboard header */}
      <Typography variant="h4" component="h1" gutterBottom>
        User Dashboard 👥
      </Typography>
      
      {/* 🔍 Search bar */}
      <TextField
        fullWidth
        variant="outlined"
        placeholder="Search users... 🔍"
        value={searchTerm}
        onChange={(e) => setSearchTerm(e.target.value)}
        sx={{ mb: 3 }}
        InputProps={{
          startAdornment: (
            <InputAdornment position="start">
              <Search />
            </InputAdornment>
          ),
        }}
      />

      {/* 📊 Users table */}
      <TableContainer component={Paper}>
        <Table>
          <TableHead>
            <TableRow>
              <TableCell>User 👤</TableCell>
              <TableCell>Email 📧</TableCell>
              <TableCell>Role 💼</TableCell>
              <TableCell>Status 📊</TableCell>
              <TableCell>Join Date 📅</TableCell>
              <TableCell>Actions</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {filteredUsers.map((user) => (
              <TableRow key={user.id} hover>
                <TableCell>
                  <Box sx={{ display: 'flex', alignItems: 'center' }}>
                    <Avatar 
                      src={user.avatar} 
                      sx={{ mr: 2, bgcolor: 'primary.main' }}
                    >
                      {user.name.charAt(0).toUpperCase()}
                    </Avatar>
                    <Typography variant="body1">
                      {user.name}
                    </Typography>
                  </Box>
                </TableCell>
                <TableCell>{user.email}</TableCell>
                <TableCell>
                  <Chip 
                    label={user.role.toUpperCase()} 
                    variant="outlined" 
                    size="small" 
                  />
                </TableCell>
                <TableCell>
                  <Chip
                    label={user.status}
                    color={getStatusColor(user.status)}
                    size="small"
                  />
                </TableCell>
                <TableCell>
                  {user.joinDate.toLocaleDateString()}
                </TableCell>
                <TableCell>
                  <IconButton 
                    onClick={() => onEdit(user)}
                    color="primary"
                  >
                    <Edit />
                  </IconButton>
                  <IconButton 
                    onClick={() => onDelete(user.id)}
                    color="error"
                  >
                    <Delete />
                  </IconButton>
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
      
      {/* 📈 Stats summary */}
      <Typography variant="body2" sx={{ mt: 2, color: 'text.secondary' }}>
        Showing {filteredUsers.length} of {users.length} users 📊
      </Typography>
    </Box>
  );
};

🚀 Advanced Concepts

🧙‍♂️ Advanced Topic 1: Custom Theme with Module Augmentation

When you’re ready to level up, create custom theme properties:

// 🎨 Extend MUI theme with custom properties
declare module '@mui/material/styles' {
  interface Theme {
    custom: {
      gradient: string;
      shadows: {
        soft: string;
        strong: string;
      };
    };
  }

  interface ThemeOptions {
    custom?: {
      gradient?: string;
      shadows?: {
        soft?: string;
        strong?: string;
      };
    };
  }
}

// 🌈 Create enhanced theme
const enhancedTheme = createTheme({
  palette: {
    primary: {
      main: '#6366f1',  // ✨ Indigo
    },
  },
  custom: {
    gradient: 'linear-gradient(45deg, #6366f1 30%, #8b5cf6 90%)',
    shadows: {
      soft: '0 4px 6px rgba(99, 102, 241, 0.1)',
      strong: '0 10px 25px rgba(99, 102, 241, 0.3)',
    },
  },
});

// 🎯 Using custom theme properties
const GradientButton: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  return (
    <Button
      sx={{
        background: (theme) => theme.custom.gradient,
        boxShadow: (theme) => theme.custom.shadows.soft,
        '&:hover': {
          boxShadow: (theme) => theme.custom.shadows.strong,
        },
      }}
    >
      {children}
    </Button>
  );
};

🏗️ Advanced Topic 2: Generic Form Components

For the brave developers, create reusable form components:

// 🚀 Generic form field component
interface FormFieldProps<T> {
  name: keyof T;
  label: string;
  value: T[keyof T];
  onChange: (name: keyof T, value: T[keyof T]) => void;
  type?: 'text' | 'email' | 'password' | 'number';
  required?: boolean;
  helperText?: string;
}

function FormField<T>({
  name,
  label,
  value,
  onChange,
  type = 'text',
  required = false,
  helperText
}: FormFieldProps<T>) {
  return (
    <TextField
      fullWidth
      name={String(name)}
      label={label}
      value={value}
      onChange={(e) => onChange(name, e.target.value as T[keyof T])}
      type={type}
      required={required}
      helperText={helperText}
      margin="normal"
    />
  );
}

// 🎯 Usage with type safety
interface UserForm {
  name: string;
  email: string;
  age: number;
}

const UserFormComponent: React.FC = () => {
  const [formData, setFormData] = useState<UserForm>({
    name: '',
    email: '',
    age: 0
  });

  const handleChange = (name: keyof UserForm, value: UserForm[keyof UserForm]) => {
    setFormData(prev => ({ ...prev, [name]: value }));
  };

  return (
    <Box component="form">
      <FormField
        name="name"
        label="Full Name 👤"
        value={formData.name}
        onChange={handleChange}
        required
      />
      <FormField
        name="email"
        label="Email Address 📧"
        value={formData.email}
        onChange={handleChange}
        type="email"
        required
      />
      <FormField
        name="age"
        label="Age 🎂"
        value={formData.age}
        onChange={handleChange}
        type="number"
      />
    </Box>
  );
};

⚠️ Common Pitfalls and Solutions

😱 Pitfall 1: Missing Theme Provider

// ❌ Wrong way - components won't have theme access!
const App: React.FC = () => {
  return (
    <div>
      <Button variant="contained">No theme! 😰</Button>
    </div>
  );
};

// ✅ Correct way - wrap with ThemeProvider!
const App: React.FC = () => {
  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <Button variant="contained">Themed button! 🎨</Button>
    </ThemeProvider>
  );
};

🤯 Pitfall 2: Incorrect sx Prop Usage

// ❌ Dangerous - inline styles as strings!
<Box sx="padding: 16px; margin: 8px;">  {/* 💥 TypeScript error! */}
  Bad styling
</Box>

// ✅ Safe - use sx prop correctly!
<Box sx={{ 
  padding: 2,  // ✨ Theme spacing units
  margin: 1,
  bgcolor: 'primary.main',  // 🎨 Theme colors
  borderRadius: 1
}}>
  Good styling! 🎯
</Box>

🚫 Pitfall 3: Not Using Proper Component Props

// ❌ Wrong - missing proper typing
interface BadButtonProps {
  label: string;
  [key: string]: any;  // 😱 Loses type safety!
}

// ✅ Correct - extend MUI component props
interface GoodButtonProps extends ButtonProps {
  label: string;
  emoji?: string;
}

const CustomButton: React.FC<GoodButtonProps> = ({ 
  label, 
  emoji, 
  ...buttonProps 
}) => {
  return (
    <Button {...buttonProps}>
      {emoji} {label}
    </Button>
  );
};

🛠️ Best Practices

  1. 🎯 Use Theme System: Always work within the theme for consistency
  2. 📱 Mobile First: Use MUI’s responsive breakpoints (xs, sm, md, lg, xl)
  3. ♿ Accessibility: MUI components are accessible by default - don’t break it!
  4. 🎨 Custom Components: Extend MUI components rather than building from scratch
  5. ⚡ Performance: Use React.memo for complex components
  6. 📦 Tree Shaking: Import only what you need for smaller bundles
  7. 🔒 Type Safety: Always type your custom component props properly

🧪 Hands-On Exercise

🎯 Challenge: Build a Task Management Dashboard

Create a comprehensive task management system using Material-UI and TypeScript:

📋 Requirements:

  • ✅ Task cards with priority levels (low, medium, high)
  • 🏷️ Categories with color coding (work, personal, urgent)
  • 👤 User assignment with avatars
  • 📅 Due dates with status indicators
  • 🔍 Search and filter functionality
  • 📊 Progress statistics dashboard
  • 🎨 Custom theme with your branding
  • 📱 Responsive design for mobile and desktop

🚀 Bonus Points:

  • Add drag-and-drop task reordering
  • Implement dark/light theme toggle
  • Create custom animations for task completion
  • Add notification badges for overdue tasks
  • Export tasks to CSV functionality

💡 Solution

🔍 Click to see solution
// 🎯 Our comprehensive task management system!
import React, { useState, useMemo } from 'react';
import {
  Box,
  Card,
  CardContent,
  CardActions,
  Typography,
  Chip,
  Avatar,
  Button,
  Grid,
  TextField,
  Select,
  MenuItem,
  FormControl,
  InputLabel,
  IconButton,
  LinearProgress,
  Paper,
  List,
  ListItem,
  ListItemText,
  ListItemAvatar,
  Fab
} from '@mui/material';
import {
  Add,
  Search,
  FilterList,
  CheckCircle,
  Schedule,
  Warning,
  Person
} from '@mui/icons-material';

// 📝 Task interface with full typing
interface Task {
  id: string;
  title: string;
  description: string;
  priority: 'low' | 'medium' | 'high';
  category: 'work' | 'personal' | 'urgent';
  assignee: {
    name: string;
    avatar?: string;
  };
  dueDate: Date;
  completed: boolean;
  createdAt: Date;
}

// 🎨 Task card component
const TaskCard: React.FC<{
  task: Task;
  onToggleComplete: (taskId: string) => void;
  onEdit: (task: Task) => void;
}> = ({ task, onToggleComplete, onEdit }) => {
  const getPriorityColor = (priority: Task['priority']) => {
    switch (priority) {
      case 'high': return 'error';
      case 'medium': return 'warning';
      case 'low': return 'success';
      default: return 'default';
    }
  };

  const getCategoryColor = (category: Task['category']) => {
    switch (category) {
      case 'work': return '#1976d2';
      case 'personal': return '#388e3c';
      case 'urgent': return '#d32f2f';
      default: return '#9e9e9e';
    }
  };

  const isOverdue = !task.completed && task.dueDate < new Date();

  return (
    <Card 
      sx={{ 
        mb: 2, 
        opacity: task.completed ? 0.7 : 1,
        border: isOverdue ? '2px solid #f44336' : 'none'
      }}
    >
      <CardContent>
        {/* 📋 Task header */}
        <Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
          <Typography 
            variant="h6" 
            sx={{ 
              textDecoration: task.completed ? 'line-through' : 'none',
              color: task.completed ? 'text.secondary' : 'text.primary'
            }}
          >
            {task.title}
          </Typography>
          {isOverdue && <Warning color="error" />}
        </Box>

        {/* 📝 Description */}
        <Typography variant="body2" color="text.secondary" paragraph>
          {task.description}
        </Typography>

        {/* 🏷️ Priority and category chips */}
        <Box sx={{ display: 'flex', gap: 1, mb: 2 }}>
          <Chip
            label={`${task.priority.toUpperCase()} PRIORITY`}
            color={getPriorityColor(task.priority)}
            size="small"
          />
          <Chip
            label={task.category.toUpperCase()}
            sx={{ 
              bgcolor: getCategoryColor(task.category),
              color: 'white'
            }}
            size="small"
          />
        </Box>

        {/* 👤 Assignee */}
        <Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}>
          <Avatar 
            src={task.assignee.avatar} 
            sx={{ width: 24, height: 24, mr: 1 }}
          >
            <Person />
          </Avatar>
          <Typography variant="body2">
            {task.assignee.name}
          </Typography>
        </Box>

        {/* 📅 Due date */}
        <Typography variant="body2" color={isOverdue ? 'error' : 'text.secondary'}>
          Due: {task.dueDate.toLocaleDateString()} 
          {isOverdue ? ' ⚠️ OVERDUE' : ''}
        </Typography>
      </CardContent>

      <CardActions>
        <Button
          startIcon={<CheckCircle />}
          onClick={() => onToggleComplete(task.id)}
          color={task.completed ? 'success' : 'primary'}
        >
          {task.completed ? 'Completed ✅' : 'Mark Complete'}
        </Button>
        <Button onClick={() => onEdit(task)}>
          Edit 📝
        </Button>
      </CardActions>
    </Card>
  );
};

// 📊 Dashboard statistics
const DashboardStats: React.FC<{ tasks: Task[] }> = ({ tasks }) => {
  const stats = useMemo(() => {
    const total = tasks.length;
    const completed = tasks.filter(t => t.completed).length;
    const overdue = tasks.filter(t => !t.completed && t.dueDate < new Date()).length;
    const progress = total > 0 ? (completed / total) * 100 : 0;

    return { total, completed, overdue, progress };
  }, [tasks]);

  return (
    <Paper sx={{ p: 3, mb: 3 }}>
      <Typography variant="h5" gutterBottom>
        📊 Dashboard Overview
      </Typography>
      
      <Grid container spacing={3}>
        <Grid item xs={12} sm={6} md={3}>
          <Box textAlign="center">
            <Typography variant="h3" color="primary">
              {stats.total}
            </Typography>
            <Typography variant="body2">
              Total Tasks 📋
            </Typography>
          </Box>
        </Grid>
        
        <Grid item xs={12} sm={6} md={3}>
          <Box textAlign="center">
            <Typography variant="h3" color="success.main">
              {stats.completed}
            </Typography>
            <Typography variant="body2">
              Completed
            </Typography>
          </Box>
        </Grid>
        
        <Grid item xs={12} sm={6} md={3}>
          <Box textAlign="center">
            <Typography variant="h3" color="error.main">
              {stats.overdue}
            </Typography>
            <Typography variant="body2">
              Overdue ⚠️
            </Typography>
          </Box>
        </Grid>
        
        <Grid item xs={12} sm={6} md={3}>
          <Box textAlign="center">
            <Typography variant="h3" color="info.main">
              {Math.round(stats.progress)}%
            </Typography>
            <Typography variant="body2">
              Progress 📈
            </Typography>
          </Box>
        </Grid>
      </Grid>

      <Box sx={{ mt: 3 }}>
        <Typography variant="body2" gutterBottom>
          Overall Progress
        </Typography>
        <LinearProgress 
          variant="determinate" 
          value={stats.progress} 
          sx={{ height: 8, borderRadius: 4 }}
        />
      </Box>
    </Paper>
  );
};

// 🏗️ Main task dashboard
const TaskDashboard: React.FC = () => {
  const [tasks, setTasks] = useState<Task[]>([
    {
      id: '1',
      title: 'Learn Material-UI with TypeScript',
      description: 'Complete the comprehensive tutorial and build a demo project',
      priority: 'high',
      category: 'personal',
      assignee: { name: 'You! 😊' },
      dueDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days from now
      completed: false,
      createdAt: new Date()
    }
  ]);

  const [searchTerm, setSearchTerm] = useState('');
  const [filterCategory, setFilterCategory] = useState<string>('all');
  const [filterPriority, setFilterPriority] = useState<string>('all');

  // 🔍 Filter tasks
  const filteredTasks = useMemo(() => {
    return tasks.filter(task => {
      const matchesSearch = task.title.toLowerCase().includes(searchTerm.toLowerCase()) ||
                          task.description.toLowerCase().includes(searchTerm.toLowerCase());
      const matchesCategory = filterCategory === 'all' || task.category === filterCategory;
      const matchesPriority = filterPriority === 'all' || task.priority === filterPriority;
      
      return matchesSearch && matchesCategory && matchesPriority;
    });
  }, [tasks, searchTerm, filterCategory, filterPriority]);

  const handleToggleComplete = (taskId: string) => {
    setTasks(prev => prev.map(task => 
      task.id === taskId ? { ...task, completed: !task.completed } : task
    ));
  };

  const handleEditTask = (task: Task) => {
    console.log('Editing task:', task.title, '📝');
    // Implementation would open edit dialog
  };

  return (
    <Box sx={{ maxWidth: 1200, mx: 'auto', p: 3 }}>
      <Typography variant="h3" component="h1" gutterBottom align="center">
        🎯 Task Management Dashboard
      </Typography>

      {/* 📊 Statistics */}
      <DashboardStats tasks={tasks} />

      {/* 🔍 Search and filters */}
      <Paper sx={{ p: 2, mb: 3 }}>
        <Grid container spacing={2} alignItems="center">
          <Grid item xs={12} md={6}>
            <TextField
              fullWidth
              placeholder="Search tasks... 🔍"
              value={searchTerm}
              onChange={(e) => setSearchTerm(e.target.value)}
              InputProps={{
                startAdornment: <Search sx={{ mr: 1, color: 'text.secondary' }} />
              }}
            />
          </Grid>
          
          <Grid item xs={6} md={3}>
            <FormControl fullWidth>
              <InputLabel>Category 🏷️</InputLabel>
              <Select
                value={filterCategory}
                onChange={(e) => setFilterCategory(e.target.value)}
              >
                <MenuItem value="all">All Categories</MenuItem>
                <MenuItem value="work">Work 💼</MenuItem>
                <MenuItem value="personal">Personal 👤</MenuItem>
                <MenuItem value="urgent">Urgent</MenuItem>
              </Select>
            </FormControl>
          </Grid>
          
          <Grid item xs={6} md={3}>
            <FormControl fullWidth>
              <InputLabel>Priority</InputLabel>
              <Select
                value={filterPriority}
                onChange={(e) => setFilterPriority(e.target.value)}
              >
                <MenuItem value="all">All Priorities</MenuItem>
                <MenuItem value="high">High 🔴</MenuItem>
                <MenuItem value="medium">Medium 🟡</MenuItem>
                <MenuItem value="low">Low 🟢</MenuItem>
              </Select>
            </FormControl>
          </Grid>
        </Grid>
      </Paper>

      {/* 📋 Task list */}
      <Box>
        {filteredTasks.length === 0 ? (
          <Paper sx={{ p: 4, textAlign: 'center' }}>
            <Typography variant="h6" color="text.secondary">
              No tasks found 🤷‍♂️
            </Typography>
            <Typography variant="body2" color="text.secondary">
              {searchTerm || filterCategory !== 'all' || filterPriority !== 'all' 
                ? 'Try adjusting your filters'
                : 'Create your first task to get started!'
              }
            </Typography>
          </Paper>
        ) : (
          filteredTasks.map(task => (
            <TaskCard
              key={task.id}
              task={task}
              onToggleComplete={handleToggleComplete}
              onEdit={handleEditTask}
            />
          ))
        )}
      </Box>

      {/* ➕ Add task FAB */}
      <Fab
        color="primary"
        aria-label="add task"
        sx={{ position: 'fixed', bottom: 16, right: 16 }}
        onClick={() => console.log('Add new task! ➕')}
      >
        <Add />
      </Fab>
    </Box>
  );
};

export default TaskDashboard;

🎓 Key Takeaways

You’ve learned so much! Here’s what you can now do:

  • Set up Material-UI with TypeScript in any project 💪
  • Create beautiful components with full type safety 🛡️
  • Build complex UIs using MUI’s component library 🎯
  • Customize themes with TypeScript support 🐛
  • Handle advanced patterns like generic components 🚀

Remember: Material-UI and TypeScript together create an incredibly powerful development experience. The combination gives you beautiful design with rock-solid type safety! 🤝

🤝 Next Steps

Congratulations! 🎉 You’ve mastered Material-UI with TypeScript!

Here’s what to do next:

  1. 💻 Practice with the dashboard exercise above
  2. 🏗️ Build a complete application using MUI and TypeScript
  3. 📚 Explore MUI X components (DataGrid, DatePicker, etc.)
  4. 🌟 Share your amazing creations with the community!
  5. 🎯 Next tutorial: “Styled-Components: CSS-in-JS with Types”

Remember: Every MUI expert was once a beginner. Keep building, keep experimenting, and most importantly, have fun creating beautiful user interfaces! 🚀


Happy coding! 🎉🚀✨