Hotkeys
Hotkeys are a series of one or several keys that trigger an action when pressed.
Keyboard shortcuts enable keyboard users to invoke commands using the keyboard that would otherwise require accessing a menu or using touch or a mouse. This enables sighted and advanced users to quickly navigate and interact with your app.
As you add more shortcuts to you app you can run into conflicts,
it can become a big mess if you don't keep track of which hotkeys are used and where.
Hotkeys
tries to solve this by having a single source of truth that defines
all available hotkeys throughout your app.
An extra benefit is that the documentation for your users can be generated and is always up to date.
Other features
- Supports shifted keys like ?, =, @.
- ⌥ ⇧ ⌃ ⌘ shorthands are supported.
- Won't trigger inside inputs / content editable elements.
- Hooks also work without a global config object.
- The HotkeysList can also be used to list other options, like markdown support.
Source
Theme source
@saas-ui/hotkeys
- 2.11.2 (latest)
Import#
import {useHotkeys,useHotkeysShortcut,HotkeysProvider,HotkeysList,Hotkey,createHotkeys,} from '@saas-ui/react'
Usage#
Stand alone usage#
Press S
to trigger the action.
import { Box, Flex, Kbd } from '@chakra-ui/react'import { useHotkeys, SearchInput } from '@saas-ui/react'export default function Dialog() {const searchRef = React.useRef(null)useHotkeys('S', () => {searchRef.current.focus()})return (<Box><SearchInputref={searchRef}pr="30px"rightElement={<Flex pos="absolute" right="6px"><Kbd bg="none" fontSize="md">S</Kbd></Flex>}/></Box>)}
Multiple key combinations#
To target multiple platforms it's possible to pass an array of key combinations.
Press ⌘ Enter
or Ctrl+Enter
to trigger the action.
import { Box, Tooltip, Button } from '@chakra-ui/react'import { useHotkeys } from '@saas-ui/react'export default function Dialog() {const [isLoading, setLoading] = React.useState()const key = useHotkeys(['⌘ Enter', 'Ctrl+Enter'], () => {setLoading(true)setTimeout(() => setLoading(false), 2000)})return (<Box><Tooltip label="⌘ Enter" openDelay={500}><Button isLoading={isLoading}>Save</Button></Tooltip></Box>)}
Complex key combinations#
You can combine mutiple keys using the +
sign or by adding a space.
Press cmd shift D
or Ctrl+Shift+D
to trigger the action.
import { Box, Tooltip, Button } from '@chakra-ui/react'import { useHotkeys } from '@saas-ui/react'export default function Dialog() {const [isLoading, setLoading] = React.useState()const key = useHotkeys(['cmd shift d', 'Ctrl+Shift+D'], () => {setLoading(true)setTimeout(() => setLoading(false), 2000)})return (<Box><Tooltip label="cmd shift d" openDelay={500}><Button isLoading={isLoading}>Save</Button></Tooltip></Box>)}
Prevent default#
To prevent the default behavior of a key combination you can set the preventDefault
option to true
.
import { Box, Tooltip, Button } from '@chakra-ui/react'import { useHotkeys, SearchInput } from '@saas-ui/react'export default function Search() {const [isLoading, setLoading] = React.useState()const ref = React.useRef(null)const key = useHotkeys(['ctrl+f', 'cmd f'],() => {ref.current.focus()},{ preventDefault: true })return (<Box><SearchInput ref={ref} /></Box>)}
Key sequences#
Use the then
keyword to create a sequence of keys.
Press A
then B
to trigger the action.
import { Box, Tooltip, Button } from '@chakra-ui/react'import { useHotkeys } from '@saas-ui/react'export default function Dialog() {const [isLoading, setLoading] = React.useState()const key = useHotkeys('A then B', () => {setLoading(true)setTimeout(() => setLoading(false), 2000)})return (<Box><Tooltip label={key} openDelay={500}><Button isLoading={isLoading}>Save</Button></Tooltip></Box>)}
Typesafe hotkeys configuration#
Create a config object containing all the keyboard shortcuts in your app. The keys in the config can be used as shortcuts with the included hook throughout your app.
// lib/hotkeys.tsimport { createHotkeys } from '@saas-ui/react'export const { HotkeysProvider, useHotkeys, Hotkey } = createHotkeys({general: {title: 'General',hotkeys: {help: { label: 'Help', command: '?' },search: { label: 'Search', command: '⌘ K' },},},})
Add the provider to your app.
// app.tsximport { HotkeysProvider } from './lib/hotkeys'export default function App() {return <HotkeysProvider>{children}</HotkeysProvider>}
Now you can use the useHotkeys
hook and Hotkey
component to trigger keyboard actions.
import { Kbd } from '@chakra-ui/react'import { SearchInput } from '@saas-ui/react'import { useHotkeys, Hotkey } from './lib/hotkeys'export const MyComponent = () => {const searchRef = React.useRef<HTMLInputElement>(null)const help = useHotkeys('general.help', () => {onOpen()})return (<div><div>Press <Kbd>{help}</Kbd> for help.</div><Hotkeycommand="general.search"callback={() => searchRef.current?.focus()}>{({ keys }) => <SearchInput ref={searchRef} placeholder={keys} />}</Hotkey></div>)}
HotkeysList component#
The HotkeysList
component can be used to list all available hotkeys in your app.
Press ?
to open the modal.
import {Box,Text,Modal,ModalOverlay,ModalCloseButton,ModalBody,Kbd,} from '@chakra-ui/react'import {HotkeysList,HotkeysSearch,HostkeysListItems,useHotkeysShortcut,} from '@saas-ui/react'export default function HotkeysListModal() {const searchRef = useRef(null)const { isOpen, onOpen, onClose } = useDisclosure()const help = useHotkeysShortcut('?' /* general.help */, () => {onOpen()})// for the sake of this example we don't depend on the hotkeys context here.// const { hotkeys } = useHotkeysContext()const hotkeys = {general: {title: 'General',hotkeys: {help: { label: 'Help', command: '?' },search: { label: 'Search', command: '⌘ K' },},},}return (<Box><Text>Press <strong>{help}</strong> for help</Text><Modal isOpen={isOpen} onClose={onClose} initialFocusRef={searchRef}><ModalOverlay /><ModalContent><ModalCloseButton /><ModalHeader>Keyboard shortcuts</ModalHeader><ModalBody><HotkeysList hotkeys={hotkeys}><HotkeysSearch ref={searchRef} /><HotkeysListItems /></HotkeysList></ModalBody></ModalContent></Modal></Box>)}
Accessibility#
The Hotkey
component will add the aria-keyshortcuts
attribute to the wrapped element. This attribute is used by screen readers to announce the available keyboard shortcuts. Short hand keys like ⌘
or ?
will be expanded to Meta
and Shift+/
respectively.
The hotkeys config can be used to display a list of available shortcuts in your app for discoverability.
More info: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-keyshortcuts
Was this helpful?