Skip to Content
UIComponentsSplitButton

SplitButton

Description

The split button component.

Parameters

No parameters

Example

With loading

Inspect

Source code

/packages/react-ui/SplitButton/SplitButton.tsx
import { ArrowDropDown } from "@mui/icons-material"; import { Button, ButtonGroup, type ButtonGroupProps, CircularProgress, ClickAwayListener, MenuItem, MenuList, Paper, Popper, } from "@mui/material"; import { forwardRef, type MouseEvent, useEffect, useRef, useState } from "react"; /** * Split button props. * @public */ export type SplitButtonProps = Omit<ButtonGroupProps, "onChange" | "onClick"> & { options: Array<{ key: string; value: string }>; loading?: boolean; onClick?: ( event: React.MouseEvent<HTMLButtonElement>, option: { key: string; value: string }, ) => void; onChange?: ( event: React.MouseEvent<HTMLLIElement>, option: { key: string; value: string }, ) => void; }; /** * The split button component. * @param props - The props. * @param ref - The reference. * @returns The react function component. * @public */ const SplitButton = forwardRef<HTMLButtonElement, SplitButtonProps>((props, ref) => { const { children, onClick, onChange, disabled, options, loading, variant = "contained", ...rest } = props; const [open, setOpen] = useState(false); const [selectedIndex, setSelectedIndex] = useState<number | null>(null); const anchorRef = useRef(null); // Reset selection useEffect(() => { setSelectedIndex(null); }, [options]); /** * Handle on main button click * @param event - The event. */ const handleClick = (event: MouseEvent<HTMLButtonElement>) => { if (disabled || selectedIndex === null || selectedIndex === undefined) { return; } const selectedItem = options[selectedIndex]; if (onClick) { onClick(event, selectedItem); } }; /** * Handle menu item click * @param event The event. * @param index Selected index. */ const handleMenuItemClick = (event: MouseEvent<HTMLLIElement>, index: number) => { setSelectedIndex(index); if (onChange) { onChange(event, options[index]); } setOpen(false); }; /** * Handle on toggle button click */ const handleToggle = () => setOpen((prevOpen) => !prevOpen); /** * Handle on close */ const handleClose = () => setOpen(false); return ( <> <ButtonGroup disabled={disabled} variant={variant} {...rest}> <Button ref={ref} disabled={loading} onClick={handleClick} variant={variant} sx={{ position: "relative", "&.Mui-disabled": { pointerEvents: "auto" }, color: loading ? "transparent !important" : undefined, }} > {loading && ( <CircularProgress size={16} sx={{ position: "absolute", left: "50%", transform: "translateX(-50%)", }} /> )} {children} </Button> <Button onClick={handleToggle} ref={anchorRef}> <ArrowDropDown /> </Button> </ButtonGroup> <Popper open={open} anchorEl={anchorRef.current}> <Paper> <ClickAwayListener onClickAway={handleClose}> <MenuList autoFocusItem> {options?.length > 0 ? ( options.map((option, index) => ( <MenuItem key={option.key} selected={index === selectedIndex} onClick={(e) => handleMenuItemClick(e, index)} > {option.value} </MenuItem> )) ) : ( <MenuItem disabled>Nema elemenata</MenuItem> )} </MenuList> </ClickAwayListener> </Paper> </Popper> </> ); }); SplitButton.displayName = "SplitButton"; export { SplitButton };
Last updated on