Cursor with custom icon set
<label id="icon-toggle">Custom icons:<input type="checkbox" /></label>
<div class="overflow-container">
<table>
<thead>
<tr>
<th>Category</th>
<th>Cursor type</th>
<th>Targeted elements <br>(CSS selectors)</th>
<th>Example element <br>(hover over to test)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Links</td>
<td>pointer</td>
<td><code>a</code></td>
<td><a href="#">Link</a></td>
</tr>
<tr>
<td>Interactive elements</td>
<td>default</td>
<td><code>button</code>, <code>input</code>, <code>select</code>, <code>label</code>, <code>video</code>, <code>audio</code></td>
<td><button>button</button></td>
</tr>
<tr>
<td>Text selection</td>
<td>text</td>
<td><code>textarea</code>, <code>input[type="text"]</code>, <code>input[type="password"]</code>, <code>input[type="email"]</code>, <code>input[type="number"]</code>, <code>input[type="search"]</code>, <code>input[type="tel"]</code>, <code>input[type="month"]</code></td>
<td><input type="text"id="name" name="name" size="10"/></td>
</tr>
</tbody>
</table>
</div> /* Custom cursor icons - opt-in state */
:is(.icons-on) {
/* cursor: general */
html,
body {
cursor: url("media/default.svg") 5.5 4.1, default;
}
/* cursor: links */
a {
cursor: url("media/pointer.svg") 13.6 1, pointer;
}
/* cursor: interactive elements */
button,
input,
select,
label,
video,
audio {
cursor: url("media/default.svg") 5.5 4.1, default;
}
/* cursor: text selection */
h1,
h2,
h3,
h4,
h5,
h6,
p,
code,
pre,
blockquote,
span,
div,
time,
textarea,
input:is(
[type="text"],
[type="password"],
[type="email"],
[type="search"],
[type="number"],
[type="tel"],
[type="url"],
[type="week"],
[type="month"],
) {
cursor: url("media/text.svg") 15.3 7.1, text;
}
}
/* System cursor icons - default state */
html,
html * {
cursor: auto;
}
html a {
cursor: pointer;
}
/* other styles */
body {
height: 100dvh;
margin: 0;
display: grid;
place-items: center;
background: hsl(240, 100%, 90%);
}
#icon-toggle {
position: absolute;
top: 0;
right: 0;
background-color: white;
padding: 0.5rem;
margin: 0.5rem;
border-radius: 4px;
box-shadow: 0 0 2px hsla(0, 0%, 0%, 0.4), 0 0 4px hsl(0, 0%, 0%, 0.2);
}
input {
width: 3rem;
}
.overflow-container {
max-width: 100%;
overflow-x: auto;
}
table {
border-collapse: collapse;
border: 1px solid rgba(0, 0, 0, 0.4);
box-shadow: 0 0 2px rgba(0, 0, 0, 0.25);
background: hsla(248, 100%, 92%);
}
thead {
background: hsla(0, 0%, 27%, 0.21);
}
th {
vertical-align: top;
}
td {
border-block-end: 1px solid #00000024;
}
th,
td {
padding: 0.5rem 1rem;
text-align: center;
}
th:nth-of-type(1),
td:nth-of-type(1) {
text-align: start;
}
td:nth-of-type(3) {
font-size: 0.9rem;
width: 3rem;
}
td:last-of-type:hover {
background: hsla(60, 100%, 70%, 0.6);
}
table:not(:first-of-type) tr:last-of-type :is(th, td) {
border-block-start: 1px dashed rgba(0, 0, 0, 0.4);
}
/* show a warning label when there is no cursor */
@media (hover: none) {
table,
label {
display: none;
}
body::before {
content: "There must be a pointing device to test the cursor styles.";
position: absolute;
top: 0;
max-width: 400px;
margin: 0.5rem;
padding: 0.1rem;
color: red;
background: rgb(246, 207, 207);
border: 1px solid red;
border-radius: 4px;
}
} let iconToggle = document.querySelector("#icon-toggle input");
iconToggle.addEventListener("click", toggleIcons);
function toggleIcons() {
document.documentElement.classList.toggle("icons-on");
} Description
Using a custom icon set for the mouse cursor.
Because accessibility is slippery with customising cursors, it might be best to require the user opt into usage. Checking the “Custom icons” checkbox will use the WinConceptOS cursor icon set that a MacOS vibe, contrary to what the name suggest!
Attribution
Uses the WinConceptOS cursors icon set under GPL-3.0 license.