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.

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>
<SearchInput
ref={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.ts
import { 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.tsx
import { 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>
<Hotkey
command="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?