Cursors
The mouse cursor reflects what an element allows, from a steady arrow on the logo to a pointing hand on an action.
On this page
Identity · default arrow
The mark, name, tagline and version keep the same cursor.
Action · pointing hand
The button opens and closes these details with a mouse, touch, Enter or Space.
Select or edit this name. Changes stay in this example.
Unavailable action
This example does not save changes.
Code
import { Box } from "@bosunkit/components/box";
import { Button } from "@bosunkit/components/button";
import { FormField } from "@bosunkit/components/form-field";
import { Input } from "@bosunkit/components/input";
import { Logo } from "@bosunkit/components/logo";
import { Stack } from "@bosunkit/components/stack";
import { Text } from "@bosunkit/components/text";
import { useId, useState, type Dispatch, type ReactElement, type SetStateAction } from "react";
export const description: string =
"Hover the logo, open the details and edit the field. The cursor follows what each element allows.";
export default function Example(): ReactElement {
const [open, setOpen]: [boolean, Dispatch<SetStateAction<boolean>>] = useState<boolean>(false);
const detailsId: string = useId();
const unavailableId: string = useId();
return (
<div role="group" aria-label="Cursor examples" style={{ width: "100%" }}>
<Stack space="lg">
<Box background="surface2" padding="lg" radius="md">
<Stack space="md">
<Text variant="label">Identity · default arrow</Text>
<Logo size="md" version="26.10.2" />
<Text variant="caption" color="text-dim">
The mark, name, tagline and version keep the same cursor.
</Text>
</Stack>
</Box>
<Box background="surface2" padding="lg" radius="md">
<Stack space="md">
<Text variant="label">Action · pointing hand</Text>
<div>
<Button
textCase="none"
motion={false}
aria-expanded={open}
aria-controls={detailsId}
onClick={(): void => {
setOpen(!open);
}}
>
{open ? "Hide details" : "Show details"}
</Button>
</div>
<div id={detailsId} hidden={!open}>
<Text>The button opens and closes these details with a mouse, touch, Enter or Space.</Text>
</div>
</Stack>
</Box>
<Box background="surface2" padding="lg" radius="md">
<FormField label="Editable text · I-beam" hint="Select or edit this name. Changes stay in this example.">
<Input defaultValue="Windgrazer" />
</FormField>
</Box>
<Box background="surface2" padding="lg" radius="md">
<Stack space="md">
<Text variant="label">Unavailable action</Text>
<div>
<Button disabled textCase="none" aria-describedby={unavailableId}>
Save changes
</Button>
</div>
<div id={unavailableId}>
<Text variant="caption" color="text-dim">
This example does not save changes.
</Text>
</div>
</Stack>
</Box>
</Stack>
</div>
);
}
Choosing a cursor
Cursor behavior is part of interaction feedback. An affordance is a clue to what someone can do; the cursor is one such clue. In Bosun, enabled buttons and links use a pointing hand, and the logo uses the default arrow.
Use the browser's standard cursor keywords. Their shapes follow the operating system, including the user's cursor
preferences. auto lets the browser choose; it can become an I-beam over selectable text. default explicitly
requests the platform's usual arrow. CSS cursor definitions
| Element or state | Cursor | Rule |
|---|---|---|
| Logo, decorative mark, empty surface | default | No action is implied. The logo's text shares the mark's arrow. |
| Enabled button, link, menu item, selectable option | pointer | The whole target performs its named action. |
| Editable or selectable text | text or native auto | Keep text selection available, including text that can be copied but not edited. |
| Disabled control | Native behavior or not-allowed | Explain why it is unavailable; the cursor alone does not disable it. |
| Pane divider | col-resize or row-resize | Match the direction the divider can move. |
| Resize edge or corner | The matching *-resize keyword | Put it on a working handle, within its actual hit area. |
| Drag handle | grab, then grabbing during a drag | Provide a way to complete the action without dragging. |
| Help target | help | Help must be available from that target. |
| Chart inspection or drawing surface | crosshair | The pointer marks a point on the drawing. |
| Lane or grid that takes a new entry | cell | Pressing an empty part marks a slot. |
These are usage rules for controls that provide each interaction, not a requirement to add dragging, help or resizing to every component. See the working pane divider for resizing.
The logo stays an arrow
The logo identifies the product. Its mark, name, tagline and version use cursor: default, so moving across them does
not turn the cursor into a text caret or a pointing hand. Text selection does not need to be disabled to achieve this.
Use a separate, labeled navigation link when navigation is needed. A logo does not become a home link merely because it appears in a header.
.logo { cursor: default; }* { cursor: default; }Disabled and pending controls
Use the component's disabled state to prevent an action. cursor: not-allowed and pointer-events: none are not
substitutes for disabled semantics or keyboard behavior. Put the reason next to the control, where it can be read
without hovering.
The kit's disabled Button ignores pointer events, so the visible cursor comes from the element beneath it. A disabled
Input uses not-allowed. Preserve these component behaviors; do not add a wrapper just to force a prohibited cursor.
For work in progress, show pending text or the component's pending state. progress means other interaction remains
available; wait means the affected area is unavailable while work finishes. Keep the status visible, and do not give
the whole page a wait cursor for local work.
CSS status cursors
Implementing and checking
Keep cursor rules in the shared component stylesheet. Consumers use the component's behavior across all themes; the cursor keywords do not need theme tokens. Use native cursors without custom images, trails or hidden pointers.
Check the entire target: its icon, text and padding should agree. Test disabled and pending states as well as the enabled state. Preserve native text selection in prose and fields; a global cursor rule can hide that feedback.
Use links for navigation and buttons for actions, with visible keyboard focus. Keep instructions and disabled reasons visible on touch screens. Every action must work from the keyboard, regardless of its cursor. WCAG 2.2 SC 2.1.1 Keyboard
Related
- Logo: the mark and text with their shared default cursor.
- Button: enabled and disabled actions.
- Panes: working resize handles and keyboard controls.
- Accessibility: focus, touch targets and keyboard operation.