CSS Cursor
What is Cursor?
The cursor property determines the type of mouse cursor displayed when the user hovers the pointer over an element. The right cursor gives users a visual hint about what they can do — click, drag, select text, and so on.
Using the right cursor is part of User Experience (UX) Design that is often overlooked, but it greatly affects how users interact with a website.
Cursor Types
Basic Cursors
| Value | Description | When to Use |
|---|---|---|
default |
Default arrow cursor | Non-interactive elements |
pointer |
Hand with a pointing finger | Links, buttons, clickable elements |
text |
I-beam | Text input areas, text selection |
wait |
Hourglass / loading | A process is running |
help |
Question mark | Elements with help/tooltip |
Action Cursors
| Value | Description | When to Use |
|---|---|---|
move |
Four-direction arrow | Elements that can be dragged |
crosshair |
Plus sign | Selection area, cropping |
grab |
Open hand | Drag handle, scrollable area |
grabbing |
Grasping hand | While a drag is in progress |
zoom-in |
Magnifying glass + | Click to zoom in |
zoom-out |
Magnifying glass - | Click to zoom out |
Resize Cursors
| Value | Description |
|---|---|
col-resize |
Horizontal arrow (change width) |
row-resize |
Vertical arrow (change height) |
e-resize / w-resize |
East/west arrow |
n-resize / s-resize |
North/south arrow |
ne-resize / sw-resize |
Northeast/southwest arrow |
nw-resize / se-resize |
Northwest/southeast arrow |
Other Cursors
| Value | Description |
|---|---|
not-allowed |
Red cross — action not allowed |
no-drop |
Cross — drop not allowed |
none |
No cursor |
alias |
Double arrow — create shortcut |
copy |
Plus sign — copy element |
progress |
Clock with arrow — loading but still interactive |
cell |
Small plus sign — select cell |
Custom Cursor
CSS allows using a custom image as a cursor:
cursor: url('custom-cursor.png'), auto;
Supported formats: PNG, SVG, GIF, and CUR. It is recommended to provide a fallback auto or default after the custom cursor.
cursor: url('cursor.png') 12 12, pointer;
/* The numbers after the URL are the hotspot (the cursor's reference point) */
Code Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS Cursor</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background-color: #f5f5f5;
padding: 20px;
color: #333;
}
h1 {
margin-bottom: 25px;
}
.section {
background-color: white;
border-radius: 8px;
padding: 20px;
margin-bottom: 25px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
}
h2 {
margin-bottom: 15px;
color: #2c3e50;
}
p {
line-height: 1.6;
color: #555;
margin-bottom: 10px;
}
code {
background-color: #f0f0f0;
padding: 2px 6px;
border-radius: 3px;
font-size: 13px;
}
/* === Basic Cursor Grid === */
.cursor-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 10px;
}
.cursor-box {
padding: 15px;
text-align: center;
background-color: #f8f9fa;
border: 2px solid #e9ecef;
border-radius: 6px;
font-size: 12px;
font-weight: bold;
color: #555;
transition: all 0.2s;
}
.cursor-box:hover {
background-color: #e9ecef;
border-color: #dee2e6;
}
.cursor-default { cursor: default; }
.cursor-pointer { cursor: pointer; }
.cursor-text { cursor: text; }
.cursor-wait { cursor: wait; }
.cursor-help { cursor: help; }
.cursor-move { cursor: move; }
.cursor-crosshair { cursor: crosshair; }
.cursor-grab { cursor: grab; }
.cursor-grabbing { cursor: grabbing; }
.cursor-zoom-in { cursor: zoom-in; }
.cursor-zoom-out { cursor: zoom-out; }
.cursor-not-allowed { cursor: not-allowed; }
.cursor-col-resize { cursor: col-resize; }
.cursor-row-resize { cursor: row-resize; }
.cursor-alias { cursor: alias; }
.cursor-copy { cursor: copy; }
.cursor-none { cursor: none; }
/* === Interactive Elements === */
.interactive-demo {
display: flex;
gap: 15px;
flex-wrap: wrap;
}
.demo-btn {
padding: 12px 24px;
border: 2px solid #3498db;
background-color: white;
color: #3498db;
border-radius: 6px;
font-size: 14px;
font-weight: bold;
cursor: pointer;
transition: all 0.2s;
}
.demo-btn:hover {
background-color: #3498db;
color: white;
}
.demo-link {
color: #3498db;
text-decoration: underline;
cursor: pointer;
font-size: 14px;
padding: 12px;
}
.demo-disabled {
padding: 12px 24px;
border: 2px solid #ddd;
background-color: #f5f5f5;
color: #bbb;
border-radius: 6px;
font-size: 14px;
cursor: not-allowed;
}
.demo-draggable {
width: 150px;
height: 80px;
background-color: #2ecc71;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 14px;
border-radius: 8px;
cursor: grab;
}
.demo-draggable:active {
cursor: grabbing;
}
.demo-text-select {
padding: 12px;
background-color: #ecf0f1;
border-radius: 6px;
cursor: text;
font-size: 14px;
user-select: text;
}
/* === Resize Handle === */
.resize-demo {
display: flex;
gap: 15px;
flex-wrap: wrap;
}
.resize-box {
background-color: #f8f9fa;
border: 2px solid #ddd;
border-radius: 6px;
padding: 10px;
font-size: 12px;
text-align: center;
color: #555;
}
.resize-col {
width: 150px;
height: 80px;
cursor: col-resize;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.resize-row {
width: 150px;
height: 80px;
cursor: row-resize;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.resize-ns {
width: 150px;
height: 80px;
cursor: ns-resize;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.resize-ew {
width: 150px;
height: 80px;
cursor: ew-resize;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.resize-nwse {
width: 150px;
height: 80px;
cursor: nwse-resize;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
/* === Zoom Demo === */
.zoom-demo {
display: flex;
gap: 15px;
flex-wrap: wrap;
}
.zoom-box {
width: 120px;
height: 120px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: bold;
color: white;
transition: transform 0.2s;
}
.zoom-in-box {
background-color: #3498db;
cursor: zoom-in;
}
.zoom-in-box:hover {
transform: scale(1.05);
}
.zoom-out-box {
background-color: #e74c3c;
cursor: zoom-out;
}
.zoom-out-box:hover {
transform: scale(0.95);
}
/* === Copy/Paste Demo === */
.copy-demo {
display: flex;
gap: 15px;
flex-wrap: wrap;
}
.copy-box {
padding: 15px;
border: 2px dashed #ddd;
border-radius: 6px;
font-size: 13px;
color: #555;
text-align: center;
transition: all 0.2s;
}
.copy-element {
cursor: copy;
background-color: #f8f9fa;
}
.copy-element:hover {
background-color: #e9ecef;
border-color: #3498db;
}
.alias-element {
cursor: alias;
background-color: #fff8e1;
}
.alias-element:hover {
background-color: #fff3cd;
border-color: #f39c12;
}
/* === Help Tooltip === */
.help-demo {
display: flex;
gap: 15px;
align-items: center;
flex-wrap: wrap;
}
.help-trigger {
cursor: help;
color: #3498db;
font-weight: bold;
font-size: 14px;
padding: 8px 16px;
background-color: #eaf4fe;
border-radius: 6px;
border: 1px dashed #3498db;
position: relative;
}
.help-trigger:hover::after {
content: 'This is a help tooltip — the cursor changes to help (?)';
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background-color: #333;
color: white;
padding: 8px 12px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
margin-bottom: 8px;
}
/* === No Cursor === */
.no-cursor-box {
width: 200px;
height: 80px;
background-color: #ecf0f1;
border: 2px solid #ddd;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
cursor: none;
font-size: 13px;
color: #555;
}
.label {
font-size: 11px;
color: #888;
text-align: center;
margin-top: 5px;
}
/* === Practical: Interactive Card === */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 15px;
}
.interactive-card {
background-color: white;
border: 2px solid #eee;
border-radius: 8px;
padding: 20px;
cursor: pointer;
transition: all 0.2s;
}
.interactive-card:hover {
border-color: #3498db;
box-shadow: 0 4px 12px rgba(52, 152, 219, 0.15);
transform: translateY(-2px);
}
.interactive-card:active {
transform: translateY(0);
cursor: grabbing;
}
.interactive-card h4 {
margin-bottom: 8px;
color: #2c3e50;
}
.interactive-card p {
font-size: 13px;
color: #666;
line-height: 1.5;
}
</style>
</head>
<body>
<h1>CSS Cursor</h1>
<!-- Basic Cursors -->
<div class="section">
<h2>Cursor Types</h2>
<p>Move your mouse over each box to see the cursor changes:</p>
<div class="cursor-grid">
<div class="cursor-box cursor-default">default<br>(Arrow cursor)</div>
<div class="cursor-box cursor-pointer">pointer<br>(Pointing hand)</div>
<div class="cursor-box cursor-text">text<br>(I-beam text)</div>
<div class="cursor-box cursor-wait">wait<br>(Loading)</div>
<div class="cursor-box cursor-help">help<br>(Help)</div>
<div class="cursor-box cursor-move">move<br>(Four directions)</div>
<div class="cursor-box cursor-crosshair">crosshair<br>(Plus)</div>
<div class="cursor-box cursor-grab">grab<br>(Open hand)</div>
<div class="cursor-box cursor-grabbing">grabbing<br>(Closed fist)</div>
<div class="cursor-box cursor-zoom-in">zoom-in<br>(Zoom in)</div>
<div class="cursor-box cursor-zoom-out">zoom-out<br>(Zoom out)</div>
<div class="cursor-box cursor-not-allowed">not-allowed<br>(Not allowed)</div>
<div class="cursor-box cursor-col-resize">col-resize<br>(Width)</div>
<div class="cursor-box cursor-row-resize">row-resize<br>(Height)</div>
<div class="cursor-box cursor-alias">alias<br>(Shortcut)</div>
<div class="cursor-box cursor-copy">copy<br>(Copy)</div>
<div class="cursor-box cursor-none">none<br>(Invisible)</div>
</div>
</div>
<!-- Interactive Elements -->
<div class="section">
<h2>Cursor on Interactive Elements</h2>
<p>The right cursor gives users a hint about the available actions:</p>
<div class="interactive-demo">
<button class="demo-btn">Click Button</button>
<a class="demo-link">Interactive Link</a>
<div class="demo-disabled">Disabled Button</div>
<div class="demo-draggable">Drag Me</div>
<div class="demo-text-select">Select this text</div>
</div>
</div>
<!-- Resize Handles -->
<div class="section">
<h2>Resize Handles</h2>
<p>Resize cursor for elements whose size can be changed:</p>
<div class="resize-demo">
<div>
<div class="resize-box resize-col">col-resize</div>
<div class="label">Horizontal</div>
</div>
<div>
<div class="resize-box resize-row">row-resize</div>
<div class="label">Vertikal</div>
</div>
<div>
<div class="resize-box resize-ns">ns-resize</div>
<div class="label">North-South</div>
</div>
<div>
<div class="resize-box resize-ew">ew-resize</div>
<div class="label">East-West</div>
</div>
<div>
<div class="resize-box resize-nwse">nwse-resize</div>
<div class="label">Diagonal</div>
</div>
</div>
</div>
<!-- Zoom -->
<div class="section">
<h2>Zoom In / Zoom Out</h2>
<p>Zoom cursor for elements that can be enlarged or reduced:</p>
<div class="zoom-demo">
<div class="zoom-box zoom-in-box">Zoom In</div>
<div class="zoom-box zoom-out-box">Zoom Out</div>
</div>
</div>
<!-- Copy/Alias -->
<div class="section">
<h2>Copy & Alias</h2>
<p>Special cursor for copy actions and shortcuts:</p>
<div class="copy-demo">
<div class="copy-box copy-element">
Copy cursor — Click to copy
</div>
<div class="copy-box alias-element">
Alias cursor — Click to open shortcut
</div>
</div>
</div>
<!-- Help -->
<div class="section">
<h2>Help Cursor</h2>
<p>Help cursor for elements that have help:</p>
<div class="help-demo">
<span>Move your mouse here:</span>
<span class="help-trigger">What is this? (?)</span>
</div>
</div>
<!-- No Cursor -->
<div class="section">
<h2>Cursor: none</h2>
<p>Hiding the cursor — useful for video players or presentations:</p>
<div class="no-cursor-box">
The cursor disappears when pointed here
</div>
</div>
<!-- Practical Card -->
<div class="section">
<h2>Practical Example — Interactive Cards</h2>
<p>Watch the cursor changes on the cards below:</p>
<div class="card-grid">
<div class="interactive-card">
<h4>CSS Basics</h4>
<p>Learn selectors, properties, and the box model.</p>
</div>
<div class="interactive-card">
<h4>Flexbox</h4>
<p>Master one-dimensional layout with flexbox.</p>
</div>
<div class="interactive-card">
<h4>CSS Grid</h4>
<p>Powerful and modern two-dimensional layout.</p>
</div>
</div>
</div>
</body>
</html>
Code Explanation
-
Cursor Types — A grid of 17 boxes with different cursor types. Users can hover their mouse over each box to feel the difference directly.
-
Interactive Elements — Five examples of elements with the appropriate cursor:
- Button —
cursor: pointerto indicate it is clickable - Link —
cursor: pointeris the default for links - Disabled —
cursor: not-allowedto indicate the action is unavailable - Draggable —
cursor: grabchanges tocursor: grabbingwhen clicked -
Text Select —
cursor: textfor a selectable area -
Resize Handles — Five boxes with different resize directions:
col-resize— For changing a column's widthrow-resize— For changing a row's heightns-resize— North-south (vertical)ew-resize— East-west (horizontal)-
nwse-resize— Diagonal -
Zoom — Two boxes that change size on hover: zoom-in scales up, zoom-out scales down.
-
Copy & Alias — Special cursors for copy and shortcut actions.
-
Help — An element with a tooltip that appears on hover, using the
helpcursor. -
None — An area where the cursor disappears completely.
-
Interactive Cards — Cards that use cursor and transform to give visual feedback on hover and when active.
Everyday Use Cases
<!DOCTYPE html>
<html lang="en">
<head>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: Arial, sans-serif;
background-color: #f5f5f5;
}
/* === Image Viewer === */
.viewer-header {
background-color: #2c3e50;
color: white;
padding: 15px 20px;
display: flex;
align-items: center;
justify-content: space-between;
}
.viewer-header h1 {
font-size: 18px;
}
.viewer-tools {
display: flex;
gap: 10px;
}
.tool-btn {
width: 36px;
height: 36px;
border-radius: 6px;
border: none;
background-color: #34495e;
color: white;
font-size: 16px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.tool-btn:hover {
background-color: #3498db;
}
.tool-btn.active {
background-color: #3498db;
}
.viewer-canvas {
background-color: #1a1a2e;
height: 400px;
display: flex;
align-items: center;
justify-content: center;
color: #666;
font-size: 16px;
cursor: crosshair;
}
.viewer-footer {
background-color: #2c3e50;
color: white;
padding: 12px 20px;
font-size: 13px;
display: flex;
justify-content: space-between;
}
/* === Spreadsheet-like Table === */
.spreadsheet {
max-width: 800px;
margin: 30px auto;
background-color: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.spreadsheet-header {
padding: 15px 20px;
background-color: #2c3e50;
color: white;
font-weight: bold;
font-size: 16px;
}
.spreadsheet-grid {
display: grid;
grid-template-columns: 120px repeat(3, 1fr);
}
.cell {
padding: 10px 14px;
border: 1px solid #eee;
font-size: 14px;
color: #333;
cursor: cell;
}
.cell:hover {
background-color: #eaf4fe;
}
.cell-header {
background-color: #f8f9fa;
font-weight: bold;
color: #2c3e50;
cursor: default;
border-bottom: 2px solid #ddd;
}
.cell-row-header {
background-color: #f8f9fa;
font-weight: bold;
color: #555;
cursor: row-resize;
}
.cell-editable {
cursor: text;
}
.cell-editable:focus {
outline: 2px solid #3498db;
outline-offset: -2px;
background-color: white;
}
</style>
</head>
<body>
<!-- Image Viewer -->
<div class="viewer-header">
<h1>Image Viewer</h1>
<div class="viewer-tools">
<button class="tool-btn active" title="Pan">✋</button>
<button class="tool-btn" title="Zoom In">🔍</button>
<button class="tool-btn" title="Crop">⬒</button>
<button class="tool-btn" title="Measure">📏</button>
</div>
</div>
<div class="viewer-canvas">
Canvas — The cursor changes according to the selected tool
</div>
<div class="viewer-footer">
<span>Zoom: 100%</span>
<span>Use scroll to zoom, drag to pan</span>
</div>
<!-- Spreadsheet Table -->
<div class="spreadsheet">
<div class="spreadsheet-header">Student Data</div>
<div class="spreadsheet-grid">
<div class="cell cell-header">Name</div>
<div class="cell cell-header">CSS</div>
<div class="cell cell-header">HTML</div>
<div class="cell cell-header">JS</div>
<div class="cell cell-row-header">John</div>
<div class="cell cell-editable" tabindex="0">92</div>
<div class="cell cell-editable" tabindex="0">88</div>
<div class="cell cell-editable" tabindex="0">95</div>
<div class="cell cell-row-header">Mike</div>
<div class="cell cell-editable" tabindex="0">85</div>
<div class="cell cell-editable" tabindex="0">90</div>
<div class="cell cell-editable" tabindex="0">78</div>
<div class="cell cell-row-header">Amy</div>
<div class="cell cell-editable" tabindex="0">97</div>
<div class="cell cell-editable" tabindex="0">93</div>
<div class="cell cell-editable" tabindex="0">91</div>
</div>
</div>
</body>
</html>
In the example above:
- Image Viewer — A toolbar with buttons using cursor: pointer, and a canvas with cursor: crosshair for crop/selection mode
- Spreadsheet Table — Header cells use cursor: row-resize or cursor: default, editable cells use cursor: text, and regular cells use cursor: cell
Cursor Usage Tips
| User Action | Appropriate Cursor |
|---|---|
| Click to navigate | pointer |
| Type text | text |
| Wait for a process | wait or progress |
| Drag & drop | grab → grabbing |
| Resize | col-resize, row-resize, etc. |
| Zoom | zoom-in, zoom-out |
| Not available | not-allowed |
| Help tooltip | help |
Conclusion
cursor: pointer— Most commonly used for links, buttons, and interactive elementscursor: text— For text input areas and text selectioncursor: grab/grabbing— For drag and drop interactionscursor: not-allowed— For disabled elements that cannot be interacted withcursor: wait/progress— To indicate a process is runningcursor: none— Hides the cursor, useful for video players or presentations- Resize cursors (
col-resize,row-resize) — For elements whose size can be changed - Custom cursors can use an image with
cursor: url('image.png'), fallback - Using the right cursor improves UX and helps users understand the available interactions