shadimage

Dashboard Sidebar

A vertical navigation sidebar for dashboard applications with user profile, search, and expandable menu items

blocks/dashboard-sidebar/dashboard-sidebar.tsx

'use client';

import * as React from 'react';

import AssessmentIcon from '@mui/icons-material/Assessment';
import ChatIcon from '@mui/icons-material/Chat';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import FileUploadIcon from '@mui/icons-material/FileUpload';
import HandshakeIcon from '@mui/icons-material/Handshake';
import LogoutIcon from '@mui/icons-material/Logout';
import PeopleIcon from '@mui/icons-material/People';
import PublicIcon from '@mui/icons-material/Public';
import SearchIcon from '@mui/icons-material/Search';
import SettingsIcon from '@mui/icons-material/Settings';
import Avatar from '@mui/material/Avatar';
import Box from '@mui/material/Box';
import Chip from '@mui/material/Chip';
import Collapse from '@mui/material/Collapse';
import InputAdornment from '@mui/material/InputAdornment';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';

export function DashboardSidebar() {
  const [customersExpanded, setCustomersExpanded] = React.useState(false);
  const [selectedItem, setSelectedItem] = React.useState('dashboard');

  const handleCustomersClick = () => {
    setCustomersExpanded(!customersExpanded);
  };

  const handleItemClick = (item: string) => {
    setSelectedItem(item);
  };

  return (
    <Box
      component="nav"
      aria-label="Main navigation"
      sx={{
        width: 280,
        height: '100vh',
        bgcolor: 'background.paper',
        display: 'flex',
        flexDirection: 'column',
        borderRight: 1,
        borderColor: 'divider',
      }}
    >
      {/* Logo/Brand */}
      <Box
        sx={{
          display: 'flex',
          alignItems: 'center',
          gap: 1.5,
          px: 3,
          py: 2.5,
        }}
      >
        <Box
          sx={{
            width: 32,
            height: 32,
            borderRadius: '50%',
            background: 'linear-gradient(135deg, #7C3AED 0%, #A855F7 100%)',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            color: 'white',
            fontSize: 20,
          }}
        >
          I
        </Box>
        <Typography
          variant="h6"
          sx={{
            fontWeight: 600,
          }}
        >
          Ipsum
        </Typography>
      </Box>
      {/* Search Field */}
      <Box sx={{ px: 2, pb: 2 }}>
        <TextField
          fullWidth
          placeholder="Search"
          size="small"
          aria-label="Search"
          slotProps={{
            input: {
              startAdornment: (
                <InputAdornment position="start">
                  <SearchIcon fontSize="small" sx={{ color: 'text.icon' }} />
                </InputAdornment>
              ),
              sx: {
                borderRadius: 99,
                bgcolor: 'grey.50',
                '& fieldset': { border: 'none' },
              },
            },
          }}
        />
      </Box>
      {/* Navigation List */}
      <List dense sx={{ px: 1, flex: 1, overflow: 'auto' }}>
        <ListItem disablePadding>
          <ListItemButton
            selected={selectedItem === 'dashboard'}
            onClick={() => handleItemClick('dashboard')}
            aria-current={selectedItem === 'dashboard' ? 'page' : undefined}
            sx={{
              borderRadius: 2,
              mb: 0.5,
            }}
          >
            <ListItemIcon sx={{ minWidth: 40 }}>
              <DashboardIcon sx={{ color: 'text.icon' }} />
            </ListItemIcon>
            <ListItemText primary="Dashboard" />
          </ListItemButton>
        </ListItem>

        <ListItem disablePadding>
          <ListItemButton
            onClick={handleCustomersClick}
            sx={{
              borderRadius: 2,
              mb: 0.5,
            }}
          >
            <ListItemIcon sx={{ minWidth: 40 }}>
              <PeopleIcon sx={{ color: 'text.icon' }} />
            </ListItemIcon>
            <ListItemText primary="Customers" />
            {customersExpanded ? (
              <ExpandLessIcon sx={{ color: 'text.icon' }} />
            ) : (
              <ExpandMoreIcon sx={{ color: 'text.icon' }} />
            )}
          </ListItemButton>
        </ListItem>
        <Collapse in={customersExpanded} timeout="auto" unmountOnExit>
          <List dense component="div" disablePadding>
            <ListItem disablePadding>
              <ListItemButton
                selected={selectedItem === 'all-customers'}
                onClick={() => handleItemClick('all-customers')}
                sx={{
                  borderRadius: 2,
                  mb: 0.5,
                  pl: 7,
                }}
              >
                <ListItemText primary="All customers" />
              </ListItemButton>
            </ListItem>
            <ListItem disablePadding>
              <ListItemButton
                selected={selectedItem === 'segments'}
                onClick={() => handleItemClick('segments')}
                sx={{
                  borderRadius: 2,
                  mb: 0.5,
                  pl: 7,
                }}
              >
                <ListItemText primary="Segments" />
              </ListItemButton>
            </ListItem>
            <ListItem disablePadding>
              <ListItemButton
                selected={selectedItem === 'analytics'}
                onClick={() => handleItemClick('analytics')}
                sx={{
                  borderRadius: 2,
                  mb: 0.5,
                  pl: 7,
                }}
              >
                <ListItemText primary="Analytics" />
              </ListItemButton>
            </ListItem>
          </List>
        </Collapse>

        <ListItem disablePadding>
          <ListItemButton
            selected={selectedItem === 'reports'}
            onClick={() => handleItemClick('reports')}
            sx={{
              borderRadius: 2,
              mb: 0.5,
            }}
          >
            <ListItemIcon sx={{ minWidth: 40 }}>
              <AssessmentIcon sx={{ color: 'text.icon' }} />
            </ListItemIcon>
            <ListItemText primary="All reports" />
          </ListItemButton>
        </ListItem>

        <ListItem disablePadding>
          <ListItemButton
            selected={selectedItem === 'geography'}
            onClick={() => handleItemClick('geography')}
            sx={{
              borderRadius: 2,
              mb: 0.5,
            }}
          >
            <ListItemIcon sx={{ minWidth: 40 }}>
              <PublicIcon sx={{ color: 'text.icon' }} />
            </ListItemIcon>
            <ListItemText primary="Geography" />
          </ListItemButton>
        </ListItem>

        <ListItem disablePadding>
          <ListItemButton
            selected={selectedItem === 'conversations'}
            onClick={() => handleItemClick('conversations')}
            sx={{
              borderRadius: 2,
              mb: 0.5,
            }}
          >
            <ListItemIcon sx={{ minWidth: 40 }}>
              <ChatIcon sx={{ color: 'text.icon' }} />
            </ListItemIcon>
            <ListItemText primary="Conversations" />
          </ListItemButton>
        </ListItem>

        <ListItem disablePadding>
          <ListItemButton
            selected={selectedItem === 'deals'}
            onClick={() => handleItemClick('deals')}
            sx={{
              borderRadius: 2,
              mb: 0.5,
            }}
          >
            <ListItemIcon sx={{ minWidth: 40 }}>
              <HandshakeIcon sx={{ color: 'text.icon' }} />
            </ListItemIcon>
            <ListItemText primary="Deals" />
          </ListItemButton>
        </ListItem>

        <ListItem disablePadding>
          <ListItemButton
            selected={selectedItem === 'export'}
            onClick={() => handleItemClick('export')}
            sx={{
              borderRadius: 2,
              mb: 0.5,
            }}
          >
            <ListItemIcon sx={{ minWidth: 40 }}>
              <FileUploadIcon sx={{ color: 'text.icon' }} />
            </ListItemIcon>
            <ListItemText primary="Export" />
          </ListItemButton>
        </ListItem>
      </List>
      {/* User Profile Section */}
      <Box
        sx={{
          borderTop: 1,
          borderColor: 'divider',
          p: 2,
        }}
        aria-label="User profile section"
      >
        <Box
          sx={{
            display: 'flex',
            alignItems: 'center',
            gap: 1.5,
            px: 1,
            py: 1.5,
          }}
        >
          <Avatar
            src="https://placehold.co/100"
            alt="John Doe"
            sx={{ width: 40, height: 40 }}
          />
          <Box sx={{ flex: 1, minWidth: 0 }}>
            <Typography
              variant="body2"
              noWrap
              sx={{
                fontWeight: 500,
              }}
            >
              John Doe
            </Typography>
            <Chip
              label="Admin"
              size="small"
              color="secondary"
              sx={{
                height: 20,
                fontSize: '0.75rem',
                fontWeight: 500,
              }}
            />
          </Box>
        </Box>

        {/* Settings and Logout */}
        <List dense sx={{ mt: 1 }}>
          <ListItem disablePadding>
            <ListItemButton
              sx={{
                borderRadius: 2,
                mb: 0.5,
              }}
            >
              <ListItemIcon sx={{ minWidth: 40 }}>
                <SettingsIcon sx={{ color: 'text.icon' }} />
              </ListItemIcon>
              <ListItemText primary="Settings" />
            </ListItemButton>
          </ListItem>

          <ListItem disablePadding>
            <ListItemButton
              sx={{
                borderRadius: 2,
                color: 'error.main',
              }}
            >
              <ListItemIcon sx={{ minWidth: 40 }}>
                <LogoutIcon sx={{ color: 'error.main' }} />
              </ListItemIcon>
              <ListItemText primary="Log out" />
            </ListItemButton>
          </ListItem>
        </List>
      </Box>
    </Box>
  );
}
Where it goes
sidebardashboard-shellkanbanprofile
Interaction
dropdown
Use cases
dashboard

DependenciesBundle weight · light

@mui/icons-material@mui/material@emotion/react@emotion/styled