CSS user-select: none: How to Prevent Text Selection

The CSS user-select: none property prevents users from highlighting and selecting text within an interface by disabling the browser's default text selection behavior on targeted elements. This article explains how the property functions at the browser level, why it is essential for modern UI components like buttons and navigational controls, how inheritance affects nested elements, and the usability considerations you must keep in mind when applying it.

How user-select: none Works

When a user clicks and drags over text, or double-clicks a word, modern browsers initiate an internal selection mechanism managed by the DOM Selection API. This mechanism generates a visible selection highlight across text nodes and prepares the highlighted text for clipboard operations.

Applying user-select: none instructs the rendering engine to exclude the designated element and its text nodes from this selection mechanism. As a result:

  • Mouse drag events over the element will not create a highlight bounding box.
  • Double-clicking or triple-clicking text will not highlight the word or paragraph.
  • "Select All" (Ctrl+A or Cmd+A) commands bypass elements styled with user-select: none.

The text remains fully rendered in the DOM, meaning screen readers can still read it, and search engine crawlers can still index it. The property strictly alters visual highlighting and selection via the user interface.

Implementation on UI Components

Interactive elements in web applications—such as buttons, tabs, accordions, and drag-and-drop handles—often suffer from accidental text highlighting during fast or repeated clicking. Disabling selection preserves an application-like feel.

.button,
.draggable-item,
.carousel-nav {
  -webkit-user-select: none; /* Safari */
  user-select: none;         /* Standard syntax */
}

Vendor prefixes, primarily -webkit-user-select, are still recommended to ensure cross-browser compatibility, especially for older versions of Safari and iOS WebKit.

Inheritance and Overriding

The user-select property is inherited by default. If you set user-select: none on a parent component, every child element within that component will also have text selection disabled.

If a component contains editable fields or content that users should be allowed to copy (such as a code snippet inside a non-selectable card), you must explicitly restore selection on the child element:

.card {
  user-select: none;
}

.card-code-output {
  user-select: text; /* Restores standard text selection */
}

The available values for user-select include:

  • none: Prevents all selection on the element and its sub-elements.
  • auto: Computes to the default selection behavior of the browser.
  • text: Allows the user to select text normally.
  • all: Selects the entire element's content with a single click.

Best Practices and Usability

While user-select: none improves the visual stability of interactive controls, it should be used conservatively:

  • Target only controls: Limit the rule to UI elements like buttons, icon labels, sliders, and navigation menus.
  • Avoid content containers: Never apply user-select: none to long-form text, error messages, transactional data, or documentation. Preventing users from copying information they need creates significant frustration.
  • Not a security measure: user-select: none does not protect content from being scraped or copied. Users can still inspect the page source, view the DOM tree in developer tools, or disable CSS entirely to copy the text.