Cursor & Pointer Events

What You'll Learn

  • Control cursor appearance with the cursor property
  • Use standard cursor values like pointer, grab, help, and wait
  • Implement custom cursors with images and SVG data URLs
  • Control click interactions with pointer-events
  • Manage text selection with user-select
  • Provide visual feedback for interactive elements
  • Match cursor styles to element functionality for better UX

Introduction to Cursor and Pointer Control

The cursor provides essential visual feedback about what users can do with elements on your page. The cursor property changes the mouse pointer appearance, while pointer-events controls whether elements respond to mouse interactions. Together with user-select, these properties give you complete control over interaction feedback.

Proper cursor styling improves user experience by clearly indicating interactive elements, drag-and-drop areas, loading states, and disabled controls. Always match the cursor to the element's functionality.

Standard Cursor Types

CSS provides a comprehensive set of built-in cursor values for common interaction patterns. These cursors are rendered natively by the browser and work consistently across operating systems.

Common Interactive Cursors

/* Most commonly used cursors */ cursor: pointer; /* Pointing hand - use for all clickable elements */ cursor: default; /* Standard arrow pointer */ cursor: text; /* I-beam for text selection */ cursor: move; /* Four-directional arrows for moveable elements */ cursor: grab; /* Open hand for draggable elements */ cursor: grabbing; /* Closed fist while actively dragging */ cursor: not-allowed; /* Prohibited circle for disabled elements */ cursor: wait; /* Loading spinner (blocks interaction) */ cursor: progress; /* Loading with arrow (allows interaction) */ cursor: help; /* Question mark for help/tooltip triggers */

Resize Cursors

/* Directional resize cursors */ cursor: n-resize; /* North (top) */ cursor: s-resize; /* South (bottom) */ cursor: e-resize; /* East (right) */ cursor: w-resize; /* West (left) */ cursor: ne-resize; /* Northeast (top-right corner) */ cursor: nw-resize; /* Northwest (top-left corner) */ cursor: se-resize; /* Southeast (bottom-right corner) */ cursor: sw-resize; /* Southwest (bottom-left corner) */ cursor: ew-resize; /* Horizontal resize */ cursor: ns-resize; /* Vertical resize */ cursor: nesw-resize; /* Diagonal ↗↙ */ cursor: nwse-resize; /* Diagonal ↖↘ */ cursor: col-resize; /* Column resize */ cursor: row-resize; /* Row resize */

Special Purpose Cursors

/* Less common but useful cursors */ cursor: crosshair; /* Precise selection (drawing tools) */ cursor: zoom-in; /* Magnifying glass with plus */ cursor: zoom-out; /* Magnifying glass with minus */ cursor: copy; /* Indicates copying action */ cursor: alias; /* Indicates shortcut/alias creation */ cursor: context-menu; /* Right-click menu available */ cursor: cell; /* Table cell selection */ cursor: none; /* Hide cursor completely */

Custom Cursors

Create custom cursor images using image files or inline SVG data URLs. Specify the cursor hotspot coordinates and provide fallback cursors.

/* Custom cursor with image file */ .custom-cursor { cursor: url('cursor.png'), pointer; /* First parameter: image URL Second parameter: fallback cursor */ } /* With hotspot coordinates (x, y) */ .custom-cursor { cursor: url('cursor.png') 16 16, pointer; /* 16 16 = center of a 32x32 cursor */ } /* Inline SVG data URL cursor */ .svg-cursor { cursor: url('data:image/svg+xml;utf8,') 16 16, auto; } /* Multiple fallbacks */ .cursor-fallbacks { cursor: url('cursor.svg'), url('cursor.png'), pointer; /* Tries SVG first, then PNG, then pointer */ }

pointer-events: Click-Through Control

The pointer-events property controls whether an element responds to mouse events. Use it to create overlays that don't block clicks, disable interactions, or allow clicks to pass through decorative elements.

/* Element ignores all mouse events */ .overlay { pointer-events: none; /* Clicks, hovers, and cursor changes pass through */ } /* Element receives mouse events (default) */ .interactive { pointer-events: auto; } /* Common use cases */ .decorative-overlay { pointer-events: none; /* Don't block clicks on content below */ } .disabled-button { pointer-events: none; /* Disable all interactions */ opacity: 0.5; } /* Re-enable for child elements */ .no-events { pointer-events: none; } .no-events .clickable { pointer-events: auto; /* This child is still interactive */ }

user-select: Text Selection Control

Control whether users can select text with the user-select property. Prevent selection on UI elements while allowing it for content.

/* Prevent text selection */ .no-select { user-select: none; -webkit-user-select: none; /* Safari */ -moz-user-select: none; /* Firefox */ -ms-user-select: none; /* IE/Edge */ } /* Allow text selection (default) */ .selectable { user-select: text; } /* Select all text on single click */ .select-all { user-select: all; /* Useful for code blocks, URLs, email addresses */ } /* Browser default behavior */ .auto { user-select: auto; } /* Common patterns */ button, .button { user-select: none; /* Buttons shouldn't have selectable text */ } .draggable { user-select: none; /* Prevent selection while dragging */ } code, .code-block { user-select: all; /* One-click selection */ }

Practical Use Cases

Combine cursor properties with interaction states to create polished, professional interfaces.

Draggable Elements

.draggable { cursor: grab; user-select: none; } .draggable:active { cursor: grabbing; }

Disabled States

button:disabled, .button.disabled { cursor: not-allowed; opacity: 0.5; pointer-events: none; /* Completely disable interactions */ }

Loading States

.loading { cursor: wait; /* Or progress */ pointer-events: none; /* Block all interactions */ }

Help Tooltips

.tooltip-trigger { cursor: help; } .tooltip-trigger:hover::after { content: attr(data-tooltip); /* Show tooltip on hover */ }

Common Patterns Reference

Quick reference for cursor and pointer patterns based on element type.

/* Buttons and clickable elements */ button, .clickable { cursor: pointer; user-select: none; } /* Links (already have cursor: pointer) */ a { cursor: pointer; /* Default */ } /* Disabled elements */ [disabled], .disabled { cursor: not-allowed; user-select: none; } /* Draggable items */ .draggable { cursor: grab; user-select: none; } .draggable:active { cursor: grabbing; } /* Text inputs */ input[type="text"], textarea { cursor: text; user-select: text; } /* Help/info icons */ .help-icon { cursor: help; user-select: none; } /* Code blocks */ pre, code { cursor: text; user-select: all; /* One-click selection */ } /* Resizable elements */ .resize-handle { cursor: nwse-resize; /* Or appropriate direction */ } /* Zoom controls */ .zoom-in { cursor: zoom-in; } .zoom-out { cursor: zoom-out; } /* Navigation/UI elements */ nav a, .menu-item { cursor: pointer; user-select: none; }

Key Takeaways