KBD
KBD visually represents keyboard input such as keys or keyboard shortcuts.
Component Type
Indicator
Platform
Web
Component
Sana Canvas
Delivery Channels
Web
Version
16.1.7Experience Surfaces
Page Body Inline
Labs package
@workday/canvas-kit-labs-react). It's safe to use, with the caveat that Labs components are experimental and may receive significant changes or be removed entirely. See the Packages Glossary for details on Main, Preview, and Labs.Anatomy

- Container: Houses the contents of the KBD component.
- Keycode: Label for a single key.
Examples
Basic Example
KBD is a container that wraps one or more KBD.Item components. Each KBD.Item represents a
single keyboard key.
Important: When displaying a group of keyboard keys (such as Ctrl + C), do not place that combination as a text into a single
KBD.Item(for example,<KBD.Item>Ctrl + C</KBD.Item>). Doing so will cause issues with RTL (right-to-left) positioning and keyboard shortcut display. Instead, wrap each key in its ownKBD.Itemand group them inside aKBDcontainer. This ensures correct rendering and layout in both LTR and RTL environments.
PressFto pay respects.
⌘CShift+PShift+Pimport {KBD} from '@workday/canvas-kit-labs-react/kbd';
import {BodyText} from '@workday/canvas-kit-react/text';
import {createStyles} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';
const containerStyles = createStyles({
gap: system.gap.md,
display: 'flex',
flexDirection: 'column',
});
export default () => {
return (
<div className={containerStyles}>
<BodyText size="small" cs={{marginBlock: 0}}>
Press
<KBD cs={{marginInline: system.padding.xxs}}>
<KBD.Item>F</KBD.Item>
</KBD>
to pay respects.
</BodyText>
<KBD>
<KBD.Item aria-label="Command">⌘</KBD.Item>
<KBD.Item>C</KBD.Item>
</KBD>
<KBD aria-keyshortcuts="Shift+P">
<KBD.Item>Shift</KBD.Item>
<span>+</span>
<KBD.Item>P</KBD.Item>
</KBD>
<KBD aria-keyshortcuts="Shift+P">
<KBD.Item>
<KBD variant="plain">
<KBD.Item>Shift</KBD.Item>
<span>+</span>
<KBD.Item>P</KBD.Item>
</KBD>
</KBD.Item>
</KBD>
</div>
);
};
Dynamic Items
KBD is built on the Collection API. Instead
of rendering KBD.Item components statically, you can pass an array of strings to the items prop
and provide a render prop as the children. Each string represents the label of a single keyboard
key.
import {KBD} from '@workday/canvas-kit-labs-react/kbd';
import {createStyles} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';
const containerStyles = createStyles({
gap: system.gap.md,
display: 'flex',
flexDirection: 'column',
});
const items = ['⌘', 'Shift', 'P'];
export default () => {
return (
<div className={containerStyles}>
<KBD items={items}>{item => <KBD.Item>{item}</KBD.Item>}</KBD>
</div>
);
};
RTL Example
You can also use the KBD component in right-to-left (RTL) layouts. This is helpful for languages
that are read from right to left.
import {KBD} from '@workday/canvas-kit-labs-react/kbd';
import {createStyles} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';
const containerStyles = createStyles({
gap: system.gap.md,
display: 'flex',
flexDirection: 'column',
});
export default () => {
return (
<div className={containerStyles} dir="rtl">
<KBD>
<KBD.Item>F</KBD.Item>
</KBD>
<KBD>
<KBD.Item>⌘</KBD.Item>
<KBD.Item>C</KBD.Item>
</KBD>
<KBD>
<KBD.Item>Shift</KBD.Item>
<span>+</span>
<KBD.Item>P</KBD.Item>
</KBD>
<KBD as="span">
<KBD.Item>
<KBD variant="plain">
<KBD.Item>Shift</KBD.Item>
<span>+</span>
<KBD.Item>P</KBD.Item>
</KBD>
</KBD.Item>
</KBD>
</div>
);
};
Size
The KBD component supports different sizes. You can adjust the size using the size prop with
options like small, medium, and large to suit various UI needs. The size is shared with each
KBD.Item through the model.
Large Size
⌘CMedium Size
Shift+ASmall Size
CtrlVimport {KBD} from '@workday/canvas-kit-labs-react/kbd';
import {Subtext} from '@workday/canvas-kit-react/text';
import {createStyles, px2rem} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';
const containerStyles = createStyles({
gap: system.gap.md,
display: 'flex',
flexDirection: 'column',
});
const rowStyles = createStyles({
display: 'flex',
alignItems: 'center',
gap: system.gap.md,
p: {
minWidth: px2rem(104),
margin: 0,
},
});
export default () => {
return (
<div className={containerStyles}>
<div className={rowStyles}>
<Subtext size="large">Large Size</Subtext>
<KBD size="large">
<KBD.Item>⌘</KBD.Item>
<KBD.Item>C</KBD.Item>
</KBD>
</div>
<div className={rowStyles}>
<Subtext size="medium">Medium Size</Subtext>
<KBD size="medium">
<KBD.Item>Shift</KBD.Item>
<span>+</span>
<KBD.Item>A</KBD.Item>
</KBD>
</div>
<div className={rowStyles}>
<Subtext size="small">Small Size</Subtext>
<KBD size="small">
<KBD.Item>Ctrl</KBD.Item>
<KBD.Item>V</KBD.Item>
</KBD>
</div>
</div>
);
};
Variant
The KBD component supports different variants through the variant prop. Use default for the
standard style or plain for a more minimal appearance. The variant is shared with each
KBD.Item through the model.
Default Variant
⌘CPlain Variant
Shift+Aimport {KBD} from '@workday/canvas-kit-labs-react/kbd';
import {Subtext} from '@workday/canvas-kit-react/text';
import {createStyles, px2rem} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';
const containerStyles = createStyles({
gap: system.gap.md,
display: 'flex',
flexDirection: 'column',
p: {
minWidth: px2rem(104),
margin: 0,
},
});
const rowStyles = createStyles({
display: 'flex',
alignItems: 'center',
gap: system.gap.md,
});
export default () => {
return (
<div className={containerStyles}>
<div className={rowStyles}>
<Subtext size="large">Default Variant</Subtext>
<KBD variant="default">
<KBD.Item>⌘</KBD.Item>
<KBD.Item>C</KBD.Item>
</KBD>
</div>
<div className={rowStyles}>
<Subtext size="large">Plain Variant</Subtext>
<KBD variant="plain">
<KBD.Item>Shift</KBD.Item>
<span>+</span>
<KBD.Item>A</KBD.Item>
</KBD>
</div>
</div>
);
};
In Tooltip
KBD can be used inside a Tooltip to communicate the keyboard shortcut associated with an
interactive control. Pair it with descriptive text so the shortcut is easy to understand.
import {KBD} from '@workday/canvas-kit-labs-react/kbd';
import {SecondaryButton} from '@workday/canvas-kit-react/button';
import {Subtext} from '@workday/canvas-kit-react/text';
import {Tooltip} from '@workday/canvas-kit-react/tooltip';
import {createStyles} from '@workday/canvas-kit-styling';
import {copyIcon} from '@workday/canvas-system-icons-web';
import {system} from '@workday/canvas-tokens-web';
const flexContainer = createStyles({
display: 'flex',
alignItems: 'center',
gap: system.gap.xs,
p: {
margin: 0,
},
});
export default () => {
return (
<Tooltip
title={
<div className={flexContainer}>
<Subtext size="large">Copy to clipboard</Subtext>
<KBD>
<KBD.Item>
<KBD variant="plain">
<KBD.Item aria-label="Command">⌘</KBD.Item>
<KBD.Item>C</KBD.Item>
</KBD>
</KBD.Item>
</KBD>
</div>
}
>
<SecondaryButton icon={copyIcon} aria-keyshortcuts="Command+C" />
</Tooltip>
);
};
Accessibility
KBD is presentational and semantic text. It renders a kbd element so assistive technology
can recognize the content as keyboard input, but it does not make a keyboard shortcut work or
expose it to the browser. It is the visual/semantic representation of a key, not the accessibility
contract for a functioning shortcut.
aria-keyshortcutsisn’t supposed to go on the presentational KBD wrapper, it should be on the interactive control with the key listener.- The
<KBD.Item>components that use glyphs need translated aria-label strings. (E.g. “Command”, “Control”, etc.)
Provide spoken labels for symbolic or abbreviated keys
Glyphs and abbreviations such as ⌘, ⌥, ⇧, and arrow keys are not
announced reliably across screen reader, browser, and OS combinations. When a KBD.Item contains
a symbol or abbreviation, add an aria-label with the spoken name of the key so it is announced
consistently:
<KBD>
<KBD.Item aria-label="Command">⌘</KBD.Item>
<KBD.Item>C</KBD.Item>
</KBD>Plain alphanumeric keys (such as C above) read correctly on their own and don’t need an
aria-label.
Expose the actual shortcut on the control it triggers
KBD only documents a shortcut visually. If the shortcut is functional, also expose it on the
relevant interactive control using
aria-keyshortcuts
so assistive technology can communicate it to users:
<button aria-keyshortcuts="Command+C">
Copy
<KBD>
<KBD.Item aria-label="Command">⌘</KBD.Item>
<KBD.Item>C</KBD.Item>
</KBD>
</button>Component API
KBD
Props
Props extend from kbd. Changing the as prop will change the element interface.
Props extend from . If a model is passed, props from KBDModelConfig are ignored.
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | ((item: string) => ReactNode) | The children of the | |
cs | | The | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | kbd |
ref | React.Ref<R = kbd> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
KBD.Item
KBD.Item renders a single keyboard key as a semantic kbd element.
Props
Props extend from kbd. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | The content of the key. This should be the label of a single keyboard key (e.g. | |
cs | | The | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | kbd |
ref | React.Ref<R = kbd> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useListItemRegister
This elemProps hook is the base of all item component hooks. It registers an item with a
collection and sets the data-id that is used by other hooks. It should always be the last
defined hook when using composeHooks (composeHooks executes hooks right to left and merges
props left to right). It is used by ListBox.Item and all *.Item subcomponents.
const useMyItem = composeHooks(
useListItemSelect, // additional hooks go here
useListItemRegister // always last
);
(
model: ,
elemProps: {
data-id: string;
data-text: string;
data-has-children: boolean;
children: ReactNode;
index: number;
disabled: boolean;
},
ref: React.Ref
) => {
ref: (instance: | null) => void;
data-id: string;
disabled: true | undefined;
aria-setsize: number | undefined;
aria-posinset: number | undefined;
data-index: number | undefined;
style: ;
id: string;
}Model
useKBDModel
The KBD model extends the Collection System.
It tracks the keyboard keys (items) and shares the size and variant of the keys with the
KBD.Item subcomponents.
const model = useKBDModel({
size: 'large',
variant: 'plain',
items: ['⌘', 'C'],
});
<KBD model={model}>{item => <KBD.Item>{item}</KBD.Item>}</KBD>
useKBDModel (config: ): Model
KBD uses a useKBDModel to track the keyboard keys (items) and to share the size and
variant with each KBD.Item. If you need direct access to the model’s state, you can create it
yourself with useKBDModel and pass it to KBD via the model prop.
const model = useKBDModel({
size: 'large',
variant: 'plain',
items: ['⌘', 'C'],
});
<KBD model={model}>{item => <KBD.Item>{item}</KBD.Item>}</KBD>;