albert.walickihire me
← all solutions
css

How to disable text selection with CSS?

Disable text selection with user-select: none, including the prefix Safari still needs, when to use it, and how user-select: all and ::selection help.

Add user-select: none to the element. Safari still needs the -webkit- prefix, so write both:

.button {
  -webkit-user-select: none;
  user-select: none;
}

The text inside the element (and its children) can no longer be highlighted with the mouse, a double click or a long press.

When it's a good idea

Use it on interface elements where selection is only ever an accident:

  • buttons and tabs,
  • drag handles and sliders, where dragging would otherwise highlight text,
  • controls people click quickly several times, like a quantity stepper, where a double click selects the number.

Don't use it on content: articles, prices, addresses, error messages, anything someone might want to copy or look up. People select text to copy it, translate it, have it read aloud, or just to keep their place while reading.

It also doesn't protect anything. The text is still in the HTML, so anyone can copy it from the page source, the developer tools or reader mode. If you're trying to stop copying, user-select: none only annoys honest visitors.

Re-enable selection inside

user-select: none also applies to everything inside the element. If one part inside a non-selectable area should stay selectable, set user-select: text on it:

.toolbar {
  -webkit-user-select: none;
  user-select: none;
}

.toolbar .file-name {
  -webkit-user-select: text;
  user-select: text;
}

Select everything with one click

user-select: all is the opposite trick. One click selects the whole element, which is perfect for things people copy in full, like an order ID, an API key or a short command:

.order-id {
  -webkit-user-select: all;
  user-select: all;
}
<p>Your order: <code class="order-id">ORD-48213-XK</code></p>

No more carefully dragging over a long string and missing the last character.

Only prevent the double-click selection

If the problem is a double click highlighting a word on something clickable, you can stop just that and keep normal selection. The detail property of the mousedown event counts the clicks:

const stepper = document.querySelector('.stepper');

stepper.addEventListener('mousedown', (event) => {
  if (event.detail > 1) {
    event.preventDefault();
  }
});

Style the selection instead

Often the real complaint is that the default blue highlight looks out of place in the design. You don't have to disable selection for that. Restyle it with ::selection:

::selection {
  background-color: #fde68a;
  color: #111827;
}

Only a few properties work inside ::selection, mainly color, background-color, text-decoration and text-shadow. Keep enough contrast between the two colors, so selected text stays readable. You can also scope it, for example .hero ::selection, to change the highlight on a dark section only.

more solutions
work with me

Got something that needs building?

Frontend builds, full-stack features in Django, design-system work. Available for work.

See my workGet in touch