CSS Cursor Reference
Hover over all 36 CSS cursor values to see live previews — search, filter by category, copy CSS code, and generate custom url() cursors
Selected Cursor
Links & Statuscursor: pointer;
The cursor is a pointing hand, indicating a link or clickable element.
Use Case
Hyperlinks, buttons, interactive cards — any clickable element
CSS
.element {
cursor: pointer;
}Tip: click any cursor card to select and copy its CSS.
Custom Cursor via url()
Use any image URL as a cursor. A fallback keyword is required in case the image fails to load.
Generated CSS
.element {
cursor: url("https://example.com/cursor.png") 0 0, default;
}Requirements: Cursor images should be 32×32px (max 128×128px). Supported formats: PNG, SVG, GIF, .cur, .ani. The fallback keyword is mandatory — browsers ignore the rule if no fallback is provided.
All Cursors by Category
General
Links & Status
Selection
Drag & Drop
Resizing
Zooming
Your drag-and-drop interface uses cursor: pointer for everything — draggable items, resize handles, clickable buttons, text links. Users can’t tell what will happen before they click because every interaction looks the same. CSS has 36 cursor values (grab, col-resize, zoom-in, not-allowed, crosshair…) but nobody remembers more than five, and the only way to see what they look like is to write CSS and hover.
Why This Tool (Not MDN’s List)
MDN lists all cursor values with descriptions, but you can’t see what each cursor looks like without applying the CSS to an element and hovering. This reference shows all 36 cursor types as hoverable tiles — move your mouse over each one to see the actual cursor change in real time. Click to copy the CSS. Everything runs in your browser.
What Is the CSS cursor Property?
The CSS cursor property sets the type of cursor the browser should display when the mouse pointer is over an element. Choosing the right cursor communicates intent — it tells users what will happen before they click, drag, or resize.
.clickable {
cursor: pointer;
}
.loading {
cursor: wait;
}
.draggable {
cursor: grab;
}
.draggable:active {
cursor: grabbing;
}
All CSS cursor Values
The cursor property accepts 36 keyword values grouped into six functional categories, plus the special url() function for custom cursors.
General Cursors
| Value | Appearance | When to Use |
|---|---|---|
auto | Browser decides | Default — browser infers from element type |
default | Arrow pointer | Explicit default arrow, reset from other cursors |
none | Hidden | Custom cursor overlays, kiosk touch interfaces |
context-menu | Arrow + menu | Elements with right-click context menus |
help | Arrow + ? | Tooltip targets, help icons, documentation |
Links & Status Cursors
| Value | Appearance | When to Use |
|---|---|---|
pointer | Pointing hand | Links, buttons, any clickable element |
progress | Arrow + spinner | Background processing (user can still interact) |
wait | Spinner/hourglass | Blocking operation (user must wait) |
The distinction between progress and wait is important: progress should be used when users can still click and interact with the page during a background process. wait is for blocking operations where the browser is unresponsive.
Selection Cursors
| Value | Appearance | When to Use |
|---|---|---|
cell | Large crosshair | Spreadsheet cells, table selection |
crosshair | Thin crosshair | Image editors, canvas tools, map coordinates |
text | I-beam (horizontal) | Selectable or editable horizontal text |
vertical-text | I-beam (vertical) | Vertical text in CJK writing modes |
Drag & Drop Cursors
| Value | Appearance | When to Use |
|---|---|---|
alias | Arrow + shortcut badge | Creating shortcuts or symbolic links |
copy | Arrow + plus badge | Drop targets where item will be copied |
move | Four-directional arrow | Draggable elements (in transit) |
no-drop | Arrow + no circle | Invalid drop target |
not-allowed | Circle with slash | Disabled actions, restricted areas |
grab | Open hand | Draggable element (idle, can grab) |
grabbing | Closed hand | Draggable element (currently being dragged) |
Always pair grab and grabbing in your CSS: apply grab by default and switch to grabbing on mousedown or :active.
.draggable-card {
cursor: grab;
}
.draggable-card:active {
cursor: grabbing;
}
Resize Cursors
The 15 resize cursors cover single-direction and bidirectional resize handles, using compass directions:
Single-direction (n, e, s, w, ne, nw, se, sw): drag moves a single edge or corner in that direction.
Bidirectional (ew-resize, ns-resize, nesw-resize, nwse-resize): double-headed arrows indicate the element can be resized in either direction along that axis.
Utility resize cursors:
col-resize— for column dividers (horizontal resize)row-resize— for row dividers (vertical resize)all-scroll— for pannable areas (four-directional)
/* Resizable panel with directional handles */
.resize-handle-right { cursor: e-resize; }
.resize-handle-bottom { cursor: s-resize; }
.resize-handle-corner { cursor: se-resize; }
.resize-handle-col { cursor: col-resize; }
Zoom Cursors
| Value | Appearance | When to Use |
|---|---|---|
zoom-in | Magnifier + plus | Content can be zoomed in (maps, images) |
zoom-out | Magnifier + minus | Content can be zoomed out (already zoomed state) |
Custom Cursors with url()
Beyond the keyword values, the cursor property accepts a url() function that points to an image file. A fallback keyword value must be provided after the URL in case the custom cursor fails to load.
.custom {
/* x y hotspot offsets are optional (defaults to 0 0) */
cursor: url("/cursors/my-cursor.png") 16 16, pointer;
}
Cursor image requirements:
- Formats:
.cur,.ani(native),.png,.svg,.gif(modern browsers) - Maximum size: 128×128px (recommended: 32×32px for predictable rendering)
- Hotspot: The pixel coordinate within the image that maps to the pointer tip. Defaults to
0 0(top-left corner)
Always provide a fallback:
/* WRONG — no fallback, cursor disappears if image fails */
.bad { cursor: url("/my-cursor.png"); }
/* CORRECT — fallback keyword after the url() */
.good { cursor: url("/my-cursor.png") 0 0, default; }
/* Multiple fallbacks (first that works wins) */
.multi { cursor: url("/a.cur"), url("/a.png") 0 0, pointer; }
Cursor Priority and Inheritance
The cursor property inherits from the parent element. The browser resolves the cursor from the innermost element outward until a non-auto value is found:
/* Parent defines wait, but child overrides with pointer */
.loading-overlay { cursor: wait; }
.loading-overlay .cancel-btn { cursor: pointer; /* overrides wait */ }
Accessibility Considerations
Cursor types convey meaning to sighted users, but they are invisible to keyboard-only users and screen reader users. Always supplement cursor changes with:
- ARIA attributes: Use
aria-disabled="true"fornot-allowed,aria-busy="true"forwait/progress - Visual indicators: Don’t rely on cursor alone to indicate state (add opacity, color, or text labels)
- Focus styles: Ensure all interactive elements have visible
:focusstyles independent of cursor
/* Combine cursor with visual disabled state */
button:disabled {
cursor: not-allowed;
opacity: 0.5;
}
Browser Support
All 36 keyword cursor values have excellent support across modern browsers (Chrome, Firefox, Safari, Edge). The grab and grabbing values required the -webkit- prefix in older WebKit browsers but are now unprefixed in all modern browsers.
Custom url() cursors are supported in all modern browsers, though behavior on HiDPI/Retina displays varies — providing @2x variants or SVG cursors is recommended for crisp display on high-density screens.
FAQ
What is the difference between cursor: default and cursor: auto?
cursor: auto delegates the cursor choice to the browser based on context — the browser shows an I-beam over selectable text, a pointer over links, and an arrow elsewhere. cursor: default always shows the platform’s default arrow cursor, regardless of context. Use auto to let the browser make smart decisions; use default to explicitly override back to the arrow.
When should I use cursor: wait vs cursor: progress?
Use cursor: wait for blocking operations where the entire page is unresponsive (e.g., a full-page synchronous operation). Use cursor: progress when something is loading in the background but the user can still scroll, click elsewhere, or interact with other parts of the page. This semantic difference helps users understand whether they need to pause or can continue working.
Why does cursor: none hide the cursor?
cursor: none removes the system cursor entirely from the element. This is useful when you’ve built a fully custom cursor using JavaScript and CSS (e.g., a large glowing circle following the mouse) and don’t want the system cursor to overlap it. Always ensure usability and accessibility when hiding the cursor.
Can I use SVG as a custom cursor?
Yes, modern browsers support SVG in url() cursor references. SVGs scale perfectly on HiDPI displays, making them the best format for custom cursors. Note that inline SVG (data URIs) also work: cursor: url("data:image/svg+xml,...") 0 0, default;.
What is the hotspot in a custom cursor?
The hotspot is the pixel coordinate within the cursor image that acts as the actual pointer tip — the precise point where clicks are registered. For a default arrow, the hotspot is typically 0 0 (top-left). For a crosshair, it would be the center. Specify hotspot as the second argument pair after url(): cursor: url("crosshair.png") 16 16, crosshair;.