Patterns
Kbd
A small keycap that shows a key of the keyboard.
Open the command menu Ctrl K
Save the changes Ctrl S
Close a dialog Esc
import { Kbd, MonoLabel, useModKey } from 'ferry-ui'
export default function KbdHero() {
const mod = useModKey()
return (
<section className="flex w-full max-w-xs flex-col gap-2 text-[13px] text-foreground-light">
<MonoLabel as="h3">Shortcuts</MonoLabel>
<p className="flex items-center justify-between">
Open the command menu <Kbd>{mod} K</Kbd>
</p>
<p className="flex items-center justify-between">
Save the changes <Kbd>{mod} S</Kbd>
</p>
<p className="flex items-center justify-between">
Close a dialog <Kbd>Esc</Kbd>
</p>
</section>
)
}Kbd next to a button, in a search field, in a menu or in help text.Kbd does not listen to the keyboard. Bind the shortcut in your code.<code> element.Import the component. It has one part.
import { Kbd } from 'ferry-ui'
<Kbd>Esc</Kbd>The children are the text of the key. The keycap is 18px high. It grows with a long name.
import { Kbd } from 'ferry-ui'
const KEYS = ['⌘', '⇧', '⌥', 'Ctrl', 'Esc', 'Tab', '↵', '↑', '↓', '/', 'Backspace']
export default function KbdKeys() {
return (
<div className="flex flex-wrap items-center gap-1.5">
{KEYS.map((key) => (
<Kbd key={key}>{key}</Kbd>
))}
</div>
)
}For a shortcut with more than one key, use one Kbd for each key. In a small space, put all the keys in one keycap.
import { Kbd } from 'ferry-ui'
export default function KbdChord() {
return (
<ul className="flex w-full max-w-xs flex-col gap-2 text-[13px] text-foreground-light">
<li className="flex items-center justify-between">
One keycap for each key
<span className="flex gap-1">
<Kbd>⇧</Kbd>
<Kbd>N</Kbd>
</span>
</li>
<li className="flex items-center justify-between">
One keycap for all the keys
<Kbd>⇧ N</Kbd>
</li>
</ul>
)
}The main modifier key is ⌘ on an Apple platform and Ctrl on the others. useModKey() returns the correct label.
On the server, the hook returns Ctrl. Thus the first render in the browser is the same as the HTML of the server.
import { Button, Kbd, toast, useModKey } from 'ferry-ui'
import { Search } from 'lucide-react'
export default function KbdModKey() {
// "⌘" on an Apple platform, "Ctrl" on the others.
const mod = useModKey()
return (
<Button icon={<Search />} onClick={() => toast.info('Search opened')}>
Search <Kbd>{mod} K</Kbd>
</Button>
)
}Write the handler of the shortcut yourself. For a shortcut in one field, use onKeyDown. For the modifier key with a letter in the full window, use useCommandShortcut.
Ctrl ↵ sends the message
import * as React from 'react'
import { Kbd, Textarea, toast, useModKey } from 'ferry-ui'
export default function KbdHandler() {
const mod = useModKey()
const [message, setMessage] = React.useState('The invoice is ready.')
// Kbd only shows the keys. This handler does the work.
function onKeyDown(event: React.KeyboardEvent<HTMLTextAreaElement>) {
if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
event.preventDefault()
toast.success('Message sent')
setMessage('')
}
}
return (
<div className="flex w-full max-w-sm flex-col gap-2">
<Textarea
aria-label="Message"
value={message}
onChange={(event) => setMessage(event.target.value)}
onKeyDown={onKeyDown}
/>
<p className="text-[13px] text-foreground-lighter">
<Kbd>{mod}</Kbd> <Kbd>↵</Kbd> sends the message
</p>
</div>
)
}Kbd is a <kbd> element.
Kbd has no props of its own. It accepts the attributes of the element it renders.