SpeedDial

SpeedDial component is used to categorize content.

Usage#

import { SpeedDial } from 'primereact/speeddial';
<SpeedDial>
    <SpeedDial.Button />
    <SpeedDial.List>
        <SpeedDial.Item>
            <SpeedDial.Action />
        </SpeedDial.Item>
    </SpeedDial.List>
</SpeedDial>

Examples#

Linear#

import { SpeedDialProps } from '@primereact/types/shared/speeddial';
import { SpeedDial } from 'primereact/speeddial';
 
const directions = [
    { direction: 'up', style: { position: 'absolute', left: 'calc(50% - 2rem)', bottom: 0 } },
    { direction: 'down', style: { position: 'absolute', left: 'calc(50% - 2rem)', top: 0 } },
    { direction: 'left', style: { position: 'absolute', top: 'calc(50% - 2rem)', right: 0 } },
    { direction: 'right', style: { position: 'absolute', top: 'calc(50% - 2rem)', left: 0 } }
];
 
export default function LinearDemo() {
    const items = [{ icon: 'pi pi-pencil' }, { icon: 'pi pi-refresh' }, { icon: 'pi pi-trash' }, { icon: 'pi pi-upload' }, { icon: 'pi pi-external-link' }];
 
    return (
        <div className="card">
            <div style={{ position: 'relative', height: '500px' }}>
                {directions.map((item, index) => (
                    <SpeedDial key={index} direction={item.direction as SpeedDialProps['direction']} style={item.style as React.CSSProperties}>
                        <SpeedDial.Button />
                        <SpeedDial.List>
                            {items.map((action) => (
                                <SpeedDial.Item key={action.icon}>
                                    <SpeedDial.Action>
                                        <i className={action.icon}></i>
                                    </SpeedDial.Action>
                                </SpeedDial.Item>
                            ))}
                        </SpeedDial.List>
                    </SpeedDial>
                ))}
            </div>
        </div>
    );
}

Circle#

Items can be displayed around the button when type is set to circle. Additional radius property defines the radius of the circle.

import { SpeedDial } from 'primereact/speeddial';
 
export default function CircleDemo() {
    const items = [{ icon: 'pi pi-pencil' }, { icon: 'pi pi-refresh' }, { icon: 'pi pi-trash' }, { icon: 'pi pi-upload' }, { icon: 'pi pi-external-link' }];
 
    return (
        <div className="card">
            <div className="flex items-center justify-center" style={{ position: 'relative', height: '500px' }}>
                <SpeedDial type="circle" radius={80} style={{ position: 'absolute' }}>
                    <SpeedDial.Button severity="warn" />
                    <SpeedDial.List>
                        {items.map((action) => (
                            <SpeedDial.Item key={action.icon}>
                                <SpeedDial.Action>
                                    <i className={action.icon}></i>
                                </SpeedDial.Action>
                            </SpeedDial.Item>
                        ))}
                    </SpeedDial.List>
                </SpeedDial>
            </div>
        </div>
    );
}

Semi Circle#

When type is defined as semi-circle, items are displayed in a half-circle around the button.

import { SpeedDial } from 'primereact/speeddial';
 
const directions = [
    { direction: 'up', style: { position: 'absolute', left: 'calc(50% - 2rem)', bottom: 0 } },
    { direction: 'down', style: { position: 'absolute', left: 'calc(50% - 2rem)', top: 0 } },
    { direction: 'left', style: { position: 'absolute', top: 'calc(50% - 2rem)', right: 0 } },
    { direction: 'right', style: { position: 'absolute', top: 'calc(50% - 2rem)', left: 0 } }
];
 
export default function SemiCircleDemo() {
    const items = [{ icon: 'pi pi-pencil' }, { icon: 'pi pi-refresh' }, { icon: 'pi pi-trash' }, { icon: 'pi pi-upload' }, { icon: 'pi pi-external-link' }];
 
    return (
        <div className="card">
            <div style={{ position: 'relative', height: '500px' }}>
                {directions.map((item) => (
                    <SpeedDial key={item.direction} radius={80} type="semi-circle" direction={item.direction} style={item.style}>
                        <SpeedDial.Button />
                        <SpeedDial.List>
                            {items.map((action) => (
                                <SpeedDial.Item key={action.icon}>
                                    <SpeedDial.Action>
                                        <i className={action.icon}></i>
                                    </SpeedDial.Action>
                                </SpeedDial.Item>
                            ))}
                        </SpeedDial.List>
                    </SpeedDial>
                ))}
            </div>
        </div>
    );
}

Quarter Circle#

Setting type as quarter-circle displays the items at one of four corners of a button based on the direction.

import { SpeedDial } from 'primereact/speeddial';
 
const directions = [
    { direction: 'up-left', style: { position: 'absolute', right: 0, bottom: 0 } },
    { direction: 'up-right', style: { position: 'absolute', left: 0, bottom: 0 } },
    { direction: 'down-left', style: { position: 'absolute', right: 0, top: 0 } },
    { direction: 'down-right', style: { position: 'absolute', left: 0, top: 0 } }
];
 
export default function QuarterCircleDemo() {
    const items = [{ icon: 'pi pi-pencil' }, { icon: 'pi pi-refresh' }, { icon: 'pi pi-trash' }, { icon: 'pi pi-upload' }, { icon: 'pi pi-external-link' }];
 
    return (
        <div className="card">
            <div style={{ position: 'relative', height: '500px' }}>
                {directions.map((item) => (
                    <SpeedDial key={item.direction} radius={120} type="quarter-circle" direction={item.direction} style={item.style}>
                        <SpeedDial.Button />
                        <SpeedDial.List>
                            {items.map((action) => (
                                <SpeedDial.Item key={action.icon}>
                                    <SpeedDial.Action>
                                        <i className={action.icon}></i>
                                    </SpeedDial.Action>
                                </SpeedDial.Item>
                            ))}
                        </SpeedDial.List>
                    </SpeedDial>
                ))}
            </div>
        </div>
    );
}

Template#

import { SpeedDialChangeEvent, SpeedDialInstance } from '@primereact/types/shared/speeddial';
import { Button } from 'primereact/button';
import { SpeedDial } from 'primereact/speeddial';
import * as React from 'react';
 
export default function TemplateDemo() {
    const [visible, setVisible] = React.useState(false);
    const items = [
        { icon: 'pi pi-pencil', label: 'Add' },
        { icon: 'pi pi-refresh', label: 'Update' },
        { icon: 'pi pi-trash', label: 'Delete' },
        { icon: 'pi pi-upload', label: 'Upload' },
        { icon: 'pi pi-external-link', label: 'External' }
    ];
 
    return (
        <div className="card">
            <div className="flex items-end justify-center" style={{ position: 'relative', height: '400px' }}>
                <SpeedDial visible={visible} onVisibleChange={(e: SpeedDialChangeEvent) => setVisible(e.value as boolean)} direction="up" transitionDelay={80} style={{ position: 'absolute' }}>
                    {(instance: SpeedDialInstance) => {
                        return (
                            <>
                                <Button variant="outlined" className="border" onClick={instance.onClick}>
                                    <svg width="35" height="40" viewBox="0 0 35 40" fill="none" xmlns="http://www.w3.org/2000/svg">
                                        <path
                                            d="M25.87 18.05L23.16 17.45L25.27 20.46V29.78L32.49 23.76V13.53L29.18 14.73L25.87 18.04V18.05ZM25.27 35.49L29.18 31.58V27.67L25.27 30.98V35.49ZM20.16 17.14H20.03H20.17H20.16ZM30.1 5.19L34.89 4.81L33.08 12.33L24.1 15.67L30.08 5.2L30.1 5.19ZM5.72 14.74L2.41 13.54V23.77L9.63 29.79V20.47L11.74 17.46L9.03 18.06L5.72 14.75V14.74ZM9.63 30.98L5.72 27.67V31.58L9.63 35.49V30.98ZM4.8 5.2L10.78 15.67L1.81 12.33L0 4.81L4.79 5.19L4.8 5.2ZM24.37 21.05V34.59L22.56 37.29L20.46 39.4H14.44L12.34 37.29L10.53 34.59V21.05L12.42 18.23L17.45 26.8L22.48 18.23L24.37 21.05ZM22.85 0L22.57 0.69L17.45 13.08L12.33 0.69L12.05 0H22.85Z"
                                            fill="var(--p-primary-color)"
                                        />
                                        <path
                                            d="M30.69 4.21L24.37 4.81L22.57 0.69L22.86 0H26.48L30.69 4.21ZM23.75 5.67L22.66 3.08L18.05 14.24V17.14H19.7H20.03H20.16H20.2L24.1 15.7L30.11 5.19L23.75 5.67ZM4.21002 4.21L10.53 4.81L12.33 0.69L12.05 0H8.43002L4.22002 4.21H4.21002ZM21.9 17.4L20.6 18.2H14.3L13 17.4L12.4 18.2L12.42 18.23L17.45 26.8L22.48 18.23L22.5 18.2L21.9 17.4ZM4.79002 5.19L10.8 15.7L14.7 17.14H14.74H15.2H16.85V14.24L12.24 3.09L11.15 5.68L4.79002 5.2V5.19Z"
                                            fill="var(--p-text-color)"
                                        />
                                    </svg>
                                </Button>
                                <SpeedDial.List>
                                    {items.map((action, index) => (
                                        <SpeedDial.Item key={index} className="flex flex-col items-center justify-between gap-2 p-2 border rounded border-surface-200 dark:border-surface-700 w-20 cursor-pointer" onClick={instance?.onItemClick}>
                                            <span className={action.icon}></span>
                                            <span>{action.label}</span>
                                        </SpeedDial.Item>
                                    ))}
                                </SpeedDial.List>
                            </>
                        );
                    }}
                </SpeedDial>
            </div>
        </div>
    );
}

Tooltip#

import { SpeedDial } from 'primereact/speeddial';
import { Tooltip } from 'primereact/tooltip';
 
export default function TooltipDemo() {
    const items = [
        { icon: 'pi pi-pencil', label: 'Add' },
        { icon: 'pi pi-refresh', label: 'Update' },
        { icon: 'pi pi-trash', label: 'Delete' },
        { icon: 'pi pi-upload', label: 'Upload' },
        { icon: 'pi pi-external-link', label: 'External' }
    ];
 
    return (
        <div className="card">
            <div style={{ position: 'relative', height: '350px' }}>
                <SpeedDial direction="up" style={{ position: 'absolute', right: 0, bottom: 0 }}>
                    <SpeedDial.Button severity="help" />
                    <SpeedDial.List>
                        <Tooltip.Group>
                            {items.map((action) => (
                                <Tooltip key={action.icon} side="left">
                                    <Tooltip.Trigger as={SpeedDial.Item}>
                                        <SpeedDial.Action>
                                            <i className={action.icon}></i>
                                        </SpeedDial.Action>
                                    </Tooltip.Trigger>
                                    <Tooltip.Portal>
                                        <Tooltip.Content>
                                            <p>{action.label}</p>
                                            <Tooltip.Arrow />
                                        </Tooltip.Content>
                                    </Tooltip.Portal>
                                </Tooltip>
                            ))}
                        </Tooltip.Group>
                    </SpeedDial.List>
                </SpeedDial>
                <SpeedDial direction="up" style={{ position: 'absolute', left: 0, bottom: 0 }}>
                    <SpeedDial.Button severity="danger" />
                    <SpeedDial.List>
                        <Tooltip.Group>
                            {items.map((action) => (
                                <Tooltip key={action.icon} side="right">
                                    <Tooltip.Trigger as={SpeedDial.Item}>
                                        <SpeedDial.Action>
                                            <i className={action.icon}></i>
                                        </SpeedDial.Action>
                                    </Tooltip.Trigger>
                                    <Tooltip.Portal>
                                        <Tooltip.Content>
                                            <p>{action.label}</p>
                                            <Tooltip.Arrow />
                                        </Tooltip.Content>
                                    </Tooltip.Portal>
                                </Tooltip>
                            ))}
                        </Tooltip.Group>
                    </SpeedDial.List>
                </SpeedDial>
            </div>
        </div>
    );
}

Accessibility#

Screen Reader#

SpeedDial component renders a native button element that implicitly includes any passed prop. Text to describe the button can be defined with the aria-labelledby or aria-label props. Addititonally the button includes aria-haspopup, aria-expanded for states along with aria-controls to define the relation between the popup and the button. can be added to implement custom key handlers.

The popup overlay uses menu role on the list and each action item has a menuitem role with an aria-label as the menuitem label. The id of the menu refers to the aria-controls of the button.

Keyboard Support#

KeyFunction
enterToggles the visibility of the menu.
spaceToggles the visibility of the menu.
down arrowOpens the menu and moves focus to the first item.
up arrowOpens the menu and moves focus to the last item.
right arrowOpens the menu and moves focus to the last item.
left arrowOpens the menu and moves focus to the first item.
escapeCloses the menu.
KeyFunction
enterActives the menuitem, closes the menu and sets focus on the menu button.
spaceActives the menuitem, closes the menu and sets focus on the menu button.
escapeCloses the menu and sets focus on the menu button.
arrow keysNavigates between the menu items.
homeMoves focus to the first item.
endMoves focus to the last item.