IconButtonFloating
IconButtonFloating represents the primary or most common action on the screen. As the name suggests, it floats over the content and is always on top of everything on the screen. Similar to IconButton, the floating version uses icons instead of text to convey available actions. However, it is used when the action needs to be visible at all times in a sticky way where content can scroll underneath. IconButtonFloating remains in place on scroll.
By default, it has a circular shape with a floating elevation shadow style built-in. When pressed, it will open more related actions by triggering Dropdown or Modal.
IconButtonFloating is typically found in the Home feed, boards, and dashboards, allowing Pinners to perform core actions.
also known as Glyph button, Floating action button, FAB, Quick create
Props
Usage guidelines
- To represent a primary or common action when it has to be visible all the time on the screen on top of everything.
- Triggering a Modal or a Popover to complete a related task.
- Only if it is the most suitable way to present a screen's high-emphasis action.
- There isn't a need for a fixed IconButtonFloating visible all the time on the screen.
- To replace IconButton established patterns, such as navigation elements.
Best practices
Use when an action has to be visible at all times in a sticky way where content can scroll underneath.
Layer notification badges on top of IconButtonFloating. This pattern is typically used on IconButtons as part of a navigation component. IconButtonFloating shouldn't contain notifications found elsewhere on a screen, as it can lead to cognitive and usability issues. Users with color-blinded vision could also miss the intention of the notification since it doesn't offer a visually supportive affordance besides color.
Use IconButtonFloating for positive and supportive actions like Create, Help or Maximize.
Use IconButtonFloating for negative and destructive actions like Delete or Remove.
Accessibility
ARIA attributes
IconButtonFloating conveys the component behavior using iconography. IconButtonFloating requires accessibilityLabel
, a text description for screen readers to announce and communicate the represented
Icon. In the example below, the screen reader reads: "Create Pin menu". The label should describe the intent of the action, not the Icon itself. For example, use "Edit board" instead of "Pencil".
If IconButtonFloating is used as a control button to show/hide a Popover-based component, we recommend passing the following ARIA attributes to assist screen readers:
accessibilityControls
: informs the screen reader that IconButtonFloating controls the display of a Dropdown. Not needed if IconButtonFloating opens a Modal or other dialog. This populates aria-controls.accessibilityPopupRole
: informs the screen reader that there’s either amenu
component, like Dropdown, or adialog
component, like Modal or Popover, attached to IconButtonFloating. This populates aria-haspopup.accessibilityExpanded
: informs the screen reader whether an anchored Dropdown component is currently open or closed. This populates aria-expanded.
Keyboard interaction
IconButtonFloating should be contained within the role="contentinfo"
container on a page. This gives screen reader users the ability to skip any main content and go directly to the action buttons using the rotor. If there are multiple IconButtonFloatings, they should all be contained within the role="contentinfo"
container.
import { useRef, useState } from 'react'; import { Box, Dropdown, Flex, IconButtonFloating, Image, Mask } from 'gestalt'; const pins = [ { color: '#2b3938', height: 316, src: 'https://i.ibb.co/sQzHcFY/stock9.jpg', width: 474, name: 'the Hang Son Doong cave in Vietnam', }, { color: '#8e7439', height: 1081, src: 'https://i.ibb.co/zNDxPtn/stock10.jpg', width: 474, name: 'La Gran Muralla, Pekín, China', }, { color: '#698157', height: 711, src: 'https://i.ibb.co/M5TdMNq/stock11.jpg', width: 474, name: 'Plitvice Lakes National Park, Croatia', }, { color: '#4e5d50', height: 632, src: 'https://i.ibb.co/r0NZKrk/stock12.jpg', width: 474, name: 'Ban Gioc – Detian Falls : 2 waterfalls straddling the Vietnamese and Chinese border.', }, { color: '#6d6368', height: 710, src: 'https://i.ibb.co/zmFd0Dv/stock13.jpg', width: 474, name: 'Border of China and Vietnam', }, { color: '#2b3938', height: 316, src: 'https://i.ibb.co/sQzHcFY/stock9.jpg', width: 474, name: 'the Hang Son Doong cave in Vietnam', }, ]; export default function Example() { const [open, setOpen] = useState(false); const [selected, setSelected] = useState([]); const anchorRef = useRef(null); const onSelect = ({ item }) => { if (selected.some(({ value }) => value === item.value)) { setSelected((selectedValue) => selectedValue.filter(({ value }) => value !== item.value) ); } else { setSelected((selectedValue) => [...selectedValue, item]); } }; return ( <Box margin={3}> <Box role="main"> <Flex alignItems="center" gap={5} height="100%" justifyContent="center" width="100%" wrap > {[...new Array(3)].map(() => pins.map((pin) => ( <Mask key={pin.name} height={170} rounding={2} width={100}> <Image alt={pin.name} color="white" fit="cover" naturalHeight={1} naturalWidth={1} role="presentation" src={pin.src} /> </Mask> )) )} </Flex> </Box> <Box ref={anchorRef} bottom dangerouslySetInlineStyle={{ __style: { left: '50%', transform: 'translate(-50%)' }, }} marginBottom={2} position="fixed" role="contentinfo" > <IconButtonFloating accessibilityControls="sections-dropdown-example" accessibilityExpanded={open} accessibilityLabel="Create Pin Menu" accessibilityPopupRole="menu" icon="add" onClick={() => setOpen((prevVal) => !prevVal)} selected={open} tooltip={{ text: 'Create Pin Menu' }} /> </Box> {open && ( <Dropdown anchor={anchorRef.current} id="sections-dropdown-example" idealDirection="up" onDismiss={() => setOpen(false)} > <Dropdown.Section label="Create"> <Dropdown.Item onSelect={onSelect} option={{ value: 'Pin', label: 'Pin' }} selected={selected} /> <Dropdown.Item onSelect={onSelect} option={{ value: 'Story Pin', label: 'Story Pin' }} selected={selected} /> </Dropdown.Section> <Dropdown.Section label="Add"> <Dropdown.Item badge={{ text: 'New' }} onSelect={onSelect} option={{ value: 'Note', label: 'Note' }} selected={selected} /> </Dropdown.Section> </Dropdown> )} </Box> ); }
Localization
Be sure to localize all text strings. Note that localization can lengthen text by 20 to 30 percent.
Variants
Placement
IconButtonFloating is always placed along the bottom of the screen. A consistent position improves discoverability when IconButtonFloating appears across a wide range of surfaces. For example, an IconButtonFloating used to open resources should remain in the same spot on the page across surfaces. In most cases, only one IconButtonFloating should be present on a screen. The exception is using a centered IconButtonFloating as a primary action, like Pin or board creation.
Bottom edge placement
IconButtonFloating should typically be placed in the bottom edge of the screen (bottom right for LTR languages, and bottom left for RTL languages). This applies to supportive actions, such as opening related content and resources.
Centered placement
Use a centered placement when leading Pinners to an action or task that should remain present when scrolling, such as creating a new board.
import { useRef, useState } from 'react'; import { Box, Dropdown, Flex, IconButtonFloating, Image, Text } from 'gestalt'; const cards = [ { title: 'Newsroom', description: "Today's Top Holiday Picks", src: 'https://i.ibb.co/FY2MKr5/stock6.jpg', }, { title: 'Pinterest Trends', description: 'Checkout our 2023 predictions', src: 'https://i.ibb.co/sQzHcFY/stock9.jpg', }, ]; export default function Example() { const [open, setOpen] = useState(false); const anchorRef = useRef(null); return ( <Box margin={2}> <Flex alignItems="center" flex="grow" gap={4} justifyContent="center" width="100%" wrap > {cards.map((card) => ( <Flex.Item key={card.title} flex="grow"> <Box borderStyle="sm" color="default" minWidth={320} padding={4} rounding={4} width="100%" > <Flex alignContent="center" direction="column" gap={3} justifyContent="between" > <Text align="start" size="500"> {card.title} </Text> <Box height={170} width="100%"> <Image alt="" color="#000" fit="cover" naturalHeight={1} naturalWidth={1} role="presentation" src={card.src} /> </Box> <Text align="start" size="300"> {card.description} </Text> </Flex> </Box> </Flex.Item> ))} </Flex> <Box ref={anchorRef} bottom margin={4} position="fixed" right role="contentinfo" > <IconButtonFloating accessibilityControls="sections-dropdown-example" accessibilityExpanded={open} accessibilityLabel="Help & Resources Menu" accessibilityPopupRole="menu" icon="question-mark" onClick={() => setOpen((prevVal) => !prevVal)} selected={open} tooltip={{ text: 'Help & Resources Menu', }} /> </Box> {open && ( <Dropdown anchor={anchorRef.current} id="sections-dropdown-example" idealDirection="up" onDismiss={() => setOpen(false)} > <Dropdown.Link href="#" iconEnd="visit" onClick={() => { /* log click here */ }} option={{ value: 'Get help', label: 'Visit the Help Center' }} /> <Dropdown.Link href="#" iconEnd="visit" onClick={() => { /* log click here */ }} option={{ value: 'Get help', label: 'Create widget' }} /> </Dropdown> )} </Box> ); }
import { useRef, useState } from 'react'; import { Box, Dropdown, Flex, IconButtonFloating, Image, Mask } from 'gestalt'; const pins = [ { color: '#2b3938', height: 316, src: 'https://i.ibb.co/sQzHcFY/stock9.jpg', width: 474, name: 'the Hang Son Doong cave in Vietnam', }, { color: '#8e7439', height: 1081, src: 'https://i.ibb.co/zNDxPtn/stock10.jpg', width: 474, name: 'La Gran Muralla, Pekín, China', }, { color: '#698157', height: 711, src: 'https://i.ibb.co/M5TdMNq/stock11.jpg', width: 474, name: 'Plitvice Lakes National Park, Croatia', }, { color: '#4e5d50', height: 632, src: 'https://i.ibb.co/r0NZKrk/stock12.jpg', width: 474, name: 'Ban Gioc – Detian Falls : 2 waterfalls straddling the Vietnamese and Chinese border.', }, { color: '#6d6368', height: 710, src: 'https://i.ibb.co/zmFd0Dv/stock13.jpg', width: 474, name: 'Border of China and Vietnam', }, { color: '#2b3938', height: 316, src: 'https://i.ibb.co/sQzHcFY/stock9.jpg', width: 474, name: 'the Hang Son Doong cave in Vietnam', }, ]; export default function Example() { const [open, setOpen] = useState(false); const [selected, setSelected] = useState([]); const anchorRef = useRef(null); const onSelect = ({ item }) => { if (selected.some(({ value }) => value === item.value)) { setSelected((selectedValue) => selectedValue.filter(({ value }) => value !== item.value) ); } else { setSelected((selectedValue) => [...selectedValue, item]); } }; return ( <Box margin={3}> <Box role="main"> <Flex alignItems="center" gap={5} height="100%" justifyContent="center" width="100%" wrap > {[...new Array(3)].map(() => pins.map((pin) => ( <Mask key={pin.name} height={170} rounding={2} width={100}> <Image alt={pin.name} color="white" fit="cover" naturalHeight={1} naturalWidth={1} role="presentation" src={pin.src} /> </Mask> )) )} </Flex> </Box> <Box ref={anchorRef} bottom dangerouslySetInlineStyle={{ __style: { left: '50%', transform: 'translate(-50%)' }, }} marginBottom={2} position="fixed" role="contentinfo" > <IconButtonFloating accessibilityControls="sections-dropdown-example" accessibilityExpanded={open} accessibilityLabel="Create Pin Menu" accessibilityPopupRole="menu" icon="add" onClick={() => setOpen((prevVal) => !prevVal)} selected={open} tooltip={{ text: 'Create Pin Menu' }} /> </Box> {open && ( <Dropdown anchor={anchorRef.current} id="sections-dropdown-example" idealDirection="up" onDismiss={() => setOpen(false)} > <Dropdown.Section label="Create"> <Dropdown.Item onSelect={onSelect} option={{ value: 'Pin', label: 'Pin' }} selected={selected} /> <Dropdown.Item onSelect={onSelect} option={{ value: 'Story Pin', label: 'Story Pin' }} selected={selected} /> </Dropdown.Section> <Dropdown.Section label="Add"> <Dropdown.Item badge={{ text: 'New' }} onSelect={onSelect} option={{ value: 'Note', label: 'Note' }} selected={selected} /> </Dropdown.Section> </Dropdown> )} </Box> ); }
With tooltip
IconButtonFloating requires a tooltip to provide additional context to the user about the action.
import { useRef, useState } from 'react'; import { Box, Dropdown, Flex, IconButtonFloating } from 'gestalt'; export default function Example() { const [open, setOpen] = useState(false); const [selected, setSelected] = useState([]); const anchorRef = useRef(null); const onSelect = ({ item }) => { if (selected.some(({ value }) => value === item.value)) { setSelected((selectedValue) => selectedValue.filter(({ value }) => value !== item.value) ); } else { setSelected((selectedValue) => [...selectedValue, item]); } }; return ( <Flex alignItems="center" height="100%" justifyContent="center" width="100%" > <Box role="contentinfo"> <IconButtonFloating ref={anchorRef} accessibilityControls="sections-dropdown-example" accessibilityExpanded={open} accessibilityLabel="Create Pin Menu" accessibilityPopupRole="menu" icon="add" onClick={() => setOpen((prevVal) => !prevVal)} selected={open} tooltip={{ text: 'Create Pin Menu', }} /> </Box> {open && ( <Dropdown anchor={anchorRef.current} id="sections-dropdown-example" onDismiss={() => setOpen(false)} > <Dropdown.Section label="Create"> <Dropdown.Item onSelect={onSelect} option={{ value: 'Pin', label: 'Pin' }} selected={selected} /> <Dropdown.Item onSelect={onSelect} option={{ value: 'Story Pin', label: 'Story Pin' }} selected={selected} /> </Dropdown.Section> <Dropdown.Section label="Add"> <Dropdown.Item badge={{ text: 'New' }} onSelect={onSelect} option={{ value: 'Note', label: 'Note' }} selected={selected} /> <Dropdown.Item onSelect={onSelect} option={{ value: 'Section', label: 'Section' }} selected={selected} /> </Dropdown.Section> </Dropdown> )} </Flex> ); }
Writing
- Use a descriptive label to describe the IconButtonFloating action by beginning with a verb.
- Use the words "image" or "icon" in the description label. Instead, prefer to use verbs that describe the action, e.g. "Save" or "Edit".
Component quality checklist
Quality item | Status | Status description |
---|---|---|
Figma Library | Ready | Component is available in Figma for web and mobile web. |
Responsive Web | Ready | Component responds to changing viewport sizes in web and mobile web. |
Related
IconButton
Use IconButton when only an icon is needed instead of text, and the action does not float over other content.
Button
Button allows users to take actions and make choices using text labels to express what action will occur when the user interacts with it.
Icon
IconButtonFloating uses icons instead of text to convey available actions on a screen. Use an existing icon from the
Gestalt icon library.
Dropdown
IconButtonFloating is commonly paired with Dropdown to display a menu of options or actions.