Open In App

React MUI TableSortLabel API

Last Updated : 10 Jul, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Material-UI is a UI library providing predefined robust and customizable components for React for easier web development. The MUI design is based on top of Material Design by Google.

In this tutorial, we are going to discuss the React MUI TableSortLabel API. The sorting feature can be implemented in the Tables using the TableSortLabel. The API provides a lot of functionality and we are going to learn to implement them.

Import TableSortLabel  API

import TableSortLabel from '@mui/material/TableSortLabel';
// or
import { TableSortLabel } from '@mui/material';

Props List: Here is the list of different props used with this component. We can access them and modify them according to our needs.

  • children: It is a component similar to the table row.
  • classes: This overrides the existing styles or adds new styles to the component.
  • sx: The system prop allows defining system overrides as well as additional CSS styles. 
  • active: If set to true, the label will have an active styling.
  • direction(asc/desc): IT takes the direction of sorting.
  • hideSortIcon: If true, it hides the sort icon.
  • IconComponent: It is the icon of the TableSortLable.

Syntax: Create the TableSortLabel component as follows:

<TableSortLabel
  active={orderBy === headCell.id}
  direction={orderBy === headCell.id ? order : 'asc'}
  onClick={createSortHandler(headCell.id)}
>
  {headCell.label}
  {orderBy === headCell.id ? (
    <Box component="span" sx={visuallyHidden}>
      {order === 'desc' ? 'sorted descending' : 'sorted ascending'}
    </Box>
  ) : null}
</TableSortLabel>

Installing and Creating React app, and adding the MUI dependencies.

Step 1: Create a react project using the following command.

npx create-react-app gfg_tutorial

Step 2: Get into the project directory

cd gfg_tutorial

Step 3: Install the MUI dependencies as follows:

npm install @mui/material @emotion/react @emotion/styled @mui/lab

Step 4: Run the project as follows:

npm start

Example 1: In the following example, we have a Table with TableSortLabel.

App.js




import * as React from 'react'
import PropTypes from 'prop-types'
import {
  Box,
  Table,
  TableRow,
  TableCell,
  TableHead,
  TableContainer,
  TableBody,
  TableSortLabel,
  Paper,
  Toolbar,
} from '@mui/material'
  
import { visuallyHidden } from '@mui/utils'
  
function App() {
  return (
    <div className="App">
      <div
        className="head"
        style={{
          width: 'fit-content',
          margin: 'auto',
        }}
      >
        <h1
          style={{
            color: 'green',
          }}
        >
          GeeksforGeeks
        </h1>
        <strong>React MUI TableSortLabel API</strong>
      </div>
      <TableSorter />
    </div>
  )
}
  
function createData(name, likes) {
  return {
    name,
    likes,
  }
}
  
const rows = [
  createData('C++', 305),
  createData('Java', 452),
  createData('Python', 262),
  createData('React', 159),
  createData('Rust', 356),
]
  
function descendingComparator(a, b, orderBy) {
  if (b[orderBy] < a[orderBy]) {
    return -1
  }
  if (b[orderBy] > a[orderBy]) {
    return 1
  }
  return 0
}
  
function getComparator(order, orderBy) {
  return order === 'desc'
    ? (a, b) => descendingComparator(a, b, orderBy)
    : (a, b) => -descendingComparator(a, b, orderBy)
}
  
// This method is created for cross-browser 
// compatibility, if you don't need to support IE11, 
// you can use Array.prototype.sort() directly
  
function stableSort(array, comparator) {
  const stabilizedThis = array.map((el, index) => [el, index])
  stabilizedThis.sort((a, b) => {
    const order = comparator(a[0], b[0])
    if (order !== 0) {
      return order
    }
    return a[1] - b[1]
  })
  return stabilizedThis.map((el) => el[0])
}
  
const headCells = [
  {
    id: 'name',
    numeric: false,
    disablePadding: true,
    label: 'Name',
  },
  {
    id: 'likes',
    numeric: true,
    disablePadding: false,
    label: 'Likes',
  },
]
  
function EnhancedTableHead(props) {
  const {
    onSelectAllClick,
    order,
    orderBy,
    numSelected,
    rowCount,
    onRequestSort,
  } = props
  const createSortHandler = (property) => (event) => {
    onRequestSort(event, property)
  }
  
  return (
    <TableHead>
      <TableRow>
        {headCells.map((headCell) => (
          <TableCell
            key={headCell.id}
            align="center"
            padding={headCell.disablePadding ? 'none' : 'normal'}
            sortDirection={orderBy === headCell.id ? order : false}
          >
            <TableSortLabel
              direction={orderBy === headCell.id ? order : 'asc'}
              onClick={createSortHandler(headCell.id)}
            >
              {headCell.label}
              {orderBy === headCell.id ? (
                <Box component="span" sx={visuallyHidden}>
{order === 'desc' ? 'sorted descending' : 'sorted ascending'}
                </Box>
              ) : null}
            </TableSortLabel>
          </TableCell>
        ))}
      </TableRow>
    </TableHead>
  )
}
  
EnhancedTableHead.propTypes = {
  numSelected: PropTypes.number.isRequired,
  onRequestSort: PropTypes.func.isRequired,
  onSelectAllClick: PropTypes.func.isRequired,
  order: PropTypes.oneOf(['asc', 'desc']).isRequired,
  orderBy: PropTypes.string.isRequired,
  rowCount: PropTypes.number.isRequired,
}
  
const EnhancedTableToolbar = (props) => {
  const { numSelected } = props
  
  return <Toolbar></Toolbar>
}
  
EnhancedTableToolbar.propTypes = {
  numSelected: PropTypes.number.isRequired,
}
  
function TableSorter() {
  const [order, setOrder] = React.useState('asc')
  const [orderBy, setOrderBy] = React.useState('calories')
  const [selected, setSelected] = React.useState([])
  const [page, setPage] = React.useState(0)
  const [rowsPerPage, setRowsPerPage] = React.useState(5)
  
  const handleRequestSort = (event, property) => {
    const isAsc = orderBy === property && order === 'asc'
    setOrder(isAsc ? 'desc' : 'asc')
    setOrderBy(property)
  }
  
  const handleSelectAllClick = (event) => {
    if (event.target.checked) {
      const newSelecteds = rows.map((n) => n.name)
      setSelected(newSelecteds)
      return
    }
    setSelected([])
  }
  
  const handleClick = (event, name) => {
    const selectedIndex = selected.indexOf(name)
    let newSelected = []
  
    if (selectedIndex === -1) {
      newSelected = newSelected.concat(selected, name)
    } else if (selectedIndex === 0) {
      newSelected = newSelected.concat(selected.slice(1))
    } else if (selectedIndex === selected.length - 1) {
      newSelected = newSelected.concat(selected.slice(0, -1))
    } else if (selectedIndex > 0) {
      newSelected = newSelected.concat(
        selected.slice(0, selectedIndex),
        selected.slice(selectedIndex + 1),
      )
    }
  
    setSelected(newSelected)
  }
  
  const isSelected = (name) => selected.indexOf(name) !== -1
  
  return (
    <Box sx={{ width: '100%' }}>
      <Paper sx={{ mb: 2, px: 2 }}>
        <EnhancedTableToolbar numSelected={selected.length} />
        <TableContainer>
          <Table aria-labelledby="tableTitle">
            <EnhancedTableHead
              numSelected={selected.length}
              order={order}
              orderBy={orderBy}
              onSelectAllClick={handleSelectAllClick}
              onRequestSort={handleRequestSort}
              rowCount={rows.length}
            />
            <TableBody>
              
              {/* if you don't need to support IE11, you can 
                   replace the `stableSort` call with:
                 rows.slice().sort(getComparator(order, orderBy)) */}
                   
              {stableSort(rows, getComparator(order, orderBy))
                .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
                .map((row, index) => {
                  const isItemSelected = isSelected(row.name)
                  const labelId = `enhanced-table-checkbox-${index}`
  
                  return (
                    <TableRow
                      hover
                      onClick={(event) => handleClick(event, row.name)}
                      role="checkbox"
                      aria-checked={isItemSelected}
                      tabIndex={-1}
                      key={row.name}
                      selected={isItemSelected}
                    >
                      <TableCell
                        component="th"
                        id={labelId}
                        scope="row"
                        padding="none"
                        align="center"
                      >
                        {row.name}
                      </TableCell>
                      <TableCell align="center">
                          {row.likes}</TableCell>
                    </TableRow>
                  )
                })}
            </TableBody>
          </Table>
        </TableContainer>
      </Paper>
    </Box>
  )
}
  
export default App


Output:

 

Example 2: In the following example, we have set the active which will show the icon at the end.

App.js




import * as React from 'react'
import PropTypes from 'prop-types'
import {
  Box,
  Table,
  TableRow,
  TableCell,
  TableHead,
  TableContainer,
  TableBody,
  TableSortLabel,
  Paper,
  Toolbar,
} from '@mui/material'
  
import { visuallyHidden } from '@mui/utils'
  
function App() {
  return (
    <div className="App">
      <div
        className="head"
        style={{
          width: 'fit-content',
          margin: 'auto',
        }}
      >
        <h1
          style={{
            color: 'green',
          }}
        >
          GeeksforGeeks
        </h1>
        <strong>
            React MUI TableSortLabel API</strong>
      </div>
      <TableSorter />
    </div>
  )
}
  
function createData(name, likes) {
  return {
    name,
    likes,
  }
}
  
const rows = [
  createData('C++', 305),
  createData('Java', 452),
  createData('Python', 262),
  createData('React', 159),
  createData('Rust', 356),
]
  
function descendingComparator(a, b, orderBy) {
  if (b[orderBy] < a[orderBy]) {
    return -1
  }
  if (b[orderBy] > a[orderBy]) {
    return 1
  }
  return 0
}
  
function getComparator(order, orderBy) {
  return order === 'desc'
    ? (a, b) => descendingComparator(a, b, orderBy)
    : (a, b) => -descendingComparator(a, b, orderBy)
}
  
// This method is created for cross-browser 
// compatibility, if you don't need to support IE11, 
// you can use Array.prototype.sort() directly
  
function stableSort(array, comparator) {
  const stabilizedThis = array.map((el, index) => [el, index])
  stabilizedThis.sort((a, b) => {
    const order = comparator(a[0], b[0])
    if (order !== 0) {
      return order
    }
    return a[1] - b[1]
  })
  return stabilizedThis.map((el) => el[0])
}
  
const headCells = [
  {
    id: 'name',
    numeric: false,
    disablePadding: true,
    label: 'Name',
  },
  {
    id: 'likes',
    numeric: true,
    disablePadding: false,
    label: 'Likes',
  },
]
  
function EnhancedTableHead(props) {
  const {
    onSelectAllClick,
    order,
    orderBy,
    numSelected,
    rowCount,
    onRequestSort,
  } = props
  const createSortHandler = (property) => (event) => {
    onRequestSort(event, property)
  }
  
  return (
    <TableHead>
      <TableRow>
        {headCells.map((headCell) => (
          <TableCell
            key={headCell.id}
            align="center"
            padding={headCell.disablePadding ? 'none' : 'normal'}
            sortDirection={orderBy === headCell.id ? order : false}
          >
            <TableSortLabel
              active={orderBy === headCell.id}
              direction={orderBy === headCell.id ? order : 'asc'}
              onClick={createSortHandler(headCell.id)}
            >
              {headCell.label}
              {orderBy === headCell.id ? (
                <Box component="span" sx={visuallyHidden}>
                  {order === 'desc' ? 'sorted descending' : 'sorted ascending'}
                </Box>
              ) : null}
            </TableSortLabel>
          </TableCell>
        ))}
      </TableRow>
    </TableHead>
  )
}
  
EnhancedTableHead.propTypes = {
  numSelected: PropTypes.number.isRequired,
  onRequestSort: PropTypes.func.isRequired,
  onSelectAllClick: PropTypes.func.isRequired,
  order: PropTypes.oneOf(['asc', 'desc']).isRequired,
  orderBy: PropTypes.string.isRequired,
  rowCount: PropTypes.number.isRequired,
}
  
const EnhancedTableToolbar = (props) => {
  const { numSelected } = props
  
  return <Toolbar></Toolbar>
}
  
EnhancedTableToolbar.propTypes = {
  numSelected: PropTypes.number.isRequired,
}
  
function TableSorter() {
  const [order, setOrder] = React.useState('asc')
  const [orderBy, setOrderBy] = React.useState('calories')
  const [selected, setSelected] = React.useState([])
  const [page, setPage] = React.useState(0)
  const [rowsPerPage, setRowsPerPage] = React.useState(5)
  
  const handleRequestSort = (event, property) => {
    const isAsc = orderBy === property && order === 'asc'
    setOrder(isAsc ? 'desc' : 'asc')
    setOrderBy(property)
  }
  
  const handleSelectAllClick = (event) => {
    if (event.target.checked) {
      const newSelecteds = rows.map((n) => n.name)
      setSelected(newSelecteds)
      return
    }
    setSelected([])
  }
  
  const handleClick = (event, name) => {
    const selectedIndex = selected.indexOf(name)
    let newSelected = []
  
    if (selectedIndex === -1) {
      newSelected = newSelected.concat(selected, name)
    } else if (selectedIndex === 0) {
      newSelected = newSelected.concat(selected.slice(1))
    } else if (selectedIndex === selected.length - 1) {
      newSelected = newSelected.concat(selected.slice(0, -1))
    } else if (selectedIndex > 0) {
      newSelected = newSelected.concat(
        selected.slice(0, selectedIndex),
        selected.slice(selectedIndex + 1),
      )
    }
  
    setSelected(newSelected)
  }
  
  const isSelected = (name) => selected.indexOf(name) !== -1
  
  return (
    <Box sx={{ width: '100%' }}>
      <Paper sx={{ mb: 2, px: 2 }}>
        <EnhancedTableToolbar numSelected={selected.length} />
        <TableContainer>
          <Table aria-labelledby="tableTitle">
            <EnhancedTableHead
              numSelected={selected.length}
              order={order}
              orderBy={orderBy}
              onSelectAllClick={handleSelectAllClick}
              onRequestSort={handleRequestSort}
              rowCount={rows.length}
            />
            <TableBody>
              {/* if you don't need to support IE11, you can 
                   replace the `stableSort` call with:
                 rows.slice().sort(getComparator(order, orderBy)) */}
              {stableSort(rows, getComparator(order, orderBy))
                .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
                .map((row, index) => {
                  const isItemSelected = isSelected(row.name)
                  const labelId = `enhanced-table-checkbox-${index}`
  
                  return (
                    <TableRow
                      hover
                      onClick={(event) => handleClick(event, row.name)}
                      role="checkbox"
                      aria-checked={isItemSelected}
                      tabIndex={-1}
                      key={row.name}
                      selected={isItemSelected}
                    >
                      <TableCell
                        component="th"
                        id={labelId}
                        scope="row"
                        padding="none"
                        align="center"
                      >
                        {row.name}
                      </TableCell>
                      <TableCell align="center">
                          {row.likes}</TableCell>
                    </TableRow>
                  )
                })}
            </TableBody>
          </Table>
        </TableContainer>
      </Paper>
    </Box>
  )
}
  
export default App


Output:

 

Reference: https://mui.com/material-ui/api/table-sort-label/



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads