Skip to main content

Snackbar

Please refer to MUI's official docs for more details on component's usage guide and API documentation.

Basic Snackbar

Manage open prop with Snackbar component with the help of a state.


// React Imports
import { useState } from 'react'
import type { SyntheticEvent } from 'react'

// MUI Imports
import Button from '@mui/material/Button'
import Snackbar from '@mui/material/Snackbar'
import IconButton from '@mui/material/IconButton'

const SnackbarBasic = () => {
// States
const [open, setOpen] = useState<boolean>(false)

const handleClick = () => {
setOpen(true)
}

const handleClose = (event: Event | SyntheticEvent, reason?: string) => {
if (reason === 'clickaway') {
return
}
setOpen(false)
}

return (
<>
<Button variant='outlined' onClick={handleClick}>
Open simple snackbar
</Button>
<Snackbar
open={open}
onClose={handleClose}
message='Note archived'
autoHideDuration={3000}
action={
<>
<Button size='small' onClick={handleClose}>
Undo
</Button>
<IconButton size='small' aria-label='close' color='inherit' onClick={handleClose}>
<i className='ri-close-line text-xl' />
</IconButton>
</>
}
/>
</>
)
}

export default SnackbarBasic
Alert Snackbar

Add Alert component as a children of Snackbar component.


// React Imports
import { SyntheticEvent, useState } from 'react'

// MUI Imports
import Alert from '@mui/material/Alert'
import Button from '@mui/material/Button'
import Snackbar from '@mui/material/Snackbar'

const SnackbarAlert = () => {
// States
const [open, setOpen] = useState<boolean>(false)

const handleClick = () => {
setOpen(true)
}

const handleClose = (event?: Event | SyntheticEvent, reason?: string) => {
if (reason === 'clickaway') {
return
}
setOpen(false)
}

return (
<>
<Button variant='outlined' onClick={handleClick}>
Open alert snackbar
</Button>
<Snackbar open={open} onClose={handleClose} autoHideDuration={3000}>
<Alert variant='filled' severity='success' onClose={handleClose} className='w-full shadow-xs'>
This is a success message!
</Alert>
</Snackbar>
</>
)
}

export default SnackbarAlert
Positioned Snackbar

Use anchorOrigin prop to change the position of the snackbar.


// React Imports
import { useState } from 'react'

// MUI Imports
import Button from '@mui/material/Button'
import Snackbar from '@mui/material/Snackbar'
import type { SnackbarOrigin } from '@mui/material/Snackbar'

type State = SnackbarOrigin & {
open: boolean
}

const SnackbarPositioned = () => {
// States
const [state, setState] = useState<State>({
open: false,
vertical: 'top',
horizontal: 'center'
})
const { vertical, horizontal, open } = state

const handleClick = (newState: SnackbarOrigin) => () => {
setState({ open: true, ...newState })
}

const handleClose = () => {
setState({ ...state, open: false })
}

return (
<>
<div className='flex items-center gap-4 flex-wrap'>
<Button variant='outlined' onClick={handleClick({ vertical: 'top', horizontal: 'center' })}>
Top Center
</Button>
<Button variant='outlined' onClick={handleClick({ vertical: 'top', horizontal: 'right' })}>
Top Right
</Button>
<Button variant='outlined' onClick={handleClick({ vertical: 'bottom', horizontal: 'right' })}>
Bottom Right
</Button>
<Button variant='outlined' onClick={handleClick({ vertical: 'bottom', horizontal: 'center' })}>
Bottom Center
</Button>
<Button variant='outlined' onClick={handleClick({ vertical: 'bottom', horizontal: 'left' })}>
Bottom Left
</Button>
<Button variant='outlined' onClick={handleClick({ vertical: 'top', horizontal: 'left' })}>
Top Left
</Button>
</div>
<Snackbar
open={open}
onClose={handleClose}
message='I love snacks'
autoHideDuration={3000}
key={vertical + horizontal}
anchorOrigin={{ vertical, horizontal }}
/>
</>
)
}

export default SnackbarPositioned
Consecutive Snackbars

When multiple snackbar updates are necessary, they should appear one at a time.


// React Imports
import { useEffect, useState } from 'react'
import type { SyntheticEvent } from 'react'

// MUI Imports
import Alert from '@mui/material/Alert'
import Button from '@mui/material/Button'
import Snackbar from '@mui/material/Snackbar'

export type SnackbarMessage = {
key: number
message: string
}

const SnackbarConsecutive = () => {
// States
const [open, setOpen] = useState<boolean>(false)
const [snackPack, setSnackPack] = useState<SnackbarMessage[]>([])
const [messageInfo, setMessageInfo] = useState<SnackbarMessage | undefined>(undefined)

useEffect(() => {
if (snackPack.length && !messageInfo) {
setOpen(true)
setSnackPack(prev => prev.slice(1))
setMessageInfo({ ...snackPack[0] })
} else if (snackPack.length && messageInfo && open) {
setOpen(false)
}
}, [snackPack, messageInfo, open])

const handleClick = (message: string) => () => {
setSnackPack(prev => [...prev, { message, key: new Date().getTime() }])
}

const handleClose = (event: Event | SyntheticEvent, reason?: string) => {
if (reason === 'clickaway') {
return
}
setOpen(false)
}

const handleExited = () => {
setMessageInfo(undefined)
}

return (
<>
<div className='flex gap-4'>
<Button variant='outlined' onClick={handleClick('success')}>
Success Alert
</Button>
<Button variant='outlined' onClick={handleClick('error')}>
Error Alert
</Button>
</div>
<Snackbar
open={open}
onClose={handleClose}
autoHideDuration={3000}
TransitionProps={{ onExited: handleExited }}
key={messageInfo ? messageInfo.key : undefined}
message={messageInfo ? messageInfo.message : undefined}
>
<Alert
variant='filled'
onClose={handleClose}
className='w-full shadow-xs'
severity={messageInfo?.message === 'success' ? 'success' : 'error'}
>
This is {messageInfo?.message === 'success' ? 'a success' : 'an error'} message!
</Alert>
</Snackbar>
</>
)
}

export default SnackbarConsecutive
Change Transition

When multiple snackbar updates are necessary, they should appear one at a time.


// React Imports
import { useState } from 'react'
import type { ComponentType, ReactElement } from 'react'

// MUI Imports
import Grow from '@mui/material/Grow'
import Fade from '@mui/material/Fade'
import Slide from '@mui/material/Slide'
import Button from '@mui/material/Button'
import Snackbar from '@mui/material/Snackbar'
import type { GrowProps } from '@mui/material/Grow'
import type { FadeProps } from '@mui/material/Fade'
import type { SlideProps } from '@mui/material/Slide'

const GrowTransition = (props: GrowProps) => {
return <Grow {...props} />
}

const SlideTransition = (props: SlideProps) => {
return <Slide {...props} direction='up' />
}

const SnackbarTransition = () => {
// States
const [state, setState] = useState<{
open: boolean
Transition: ComponentType<
FadeProps & {
children?: ReactElement<any>
}
>
}>({
open: false,
Transition: Fade
})

const handleClick =
(
Transition: ComponentType<
FadeProps & {
children?: ReactElement<any>
}
>
) =>
() => {
setState({
open: true,
Transition
})
}

const handleClose = () => {
setState({
...state,
open: false
})
}

return (
<>
<div className='flex items-center gap-4 flex-wrap'>
<Button variant='outlined' onClick={handleClick(GrowTransition)}>
Grow Transition
</Button>
<Button variant='outlined' onClick={handleClick(Fade)}>
Fade Transition
</Button>
<Button variant='outlined' onClick={handleClick(SlideTransition)}>
Slide Transition
</Button>
</div>
<Snackbar
open={state.open}
onClose={handleClose}
message='I love snacks'
autoHideDuration={3000}
key={state.Transition.name}
TransitionComponent={state.Transition}
/>
</>
)
}

export default SnackbarTransition
Control Slide Direction

You can change the direction of the Slide transition.


// React Imports
import { useState } from 'react'
import type { ComponentType } from 'react'

// MUI Imports
import Button from '@mui/material/Button'
import Snackbar from '@mui/material/Snackbar'
import Slide from '@mui/material/Slide'
import type { SlideProps } from '@mui/material/Slide'

type TransitionProps = Omit<SlideProps, 'direction'>

const TransitionLeft = (props: TransitionProps) => {
return <Slide {...props} direction='left' />
}

const TransitionUp = (props: TransitionProps) => {
return <Slide {...props} direction='up' />
}

const TransitionRight = (props: TransitionProps) => {
return <Slide {...props} direction='right' />
}

const TransitionDown = (props: TransitionProps) => {
return <Slide {...props} direction='down' />
}

const SnackbarControlSlideDirection = () => {
// States
const [open, setOpen] = useState<boolean>(false)
const [transition, setTransition] = useState<ComponentType<TransitionProps> | undefined>(undefined)

const handleClick = (Transition: ComponentType<TransitionProps>) => () => {
setTransition(() => Transition)
setOpen(true)
}

const handleClose = () => {
setOpen(false)
}

return (
<>
<div className='flex gap-3'>
<Button variant='outlined' onClick={handleClick(TransitionLeft)}>
Right
</Button>
<Button variant='outlined' onClick={handleClick(TransitionUp)}>
Up
</Button>
<Button variant='outlined' onClick={handleClick(TransitionRight)}>
Left
</Button>
<Button variant='outlined' onClick={handleClick(TransitionDown)}>
Down
</Button>
</div>
<Snackbar
open={open}
onClose={handleClose}
message='I love snacks'
autoHideDuration={3000}
TransitionComponent={transition}
key={transition ? transition.name : ''}
/>
</>
)
}

export default SnackbarControlSlideDirection