CSS User-Select
user-select is one of those CSS properties you don’t think about… until your UI starts doing something
annoying. Like selecting text when you’re trying to drag a card. Or refusing to let people copy an invite code. Or
highlighting half the page when you double-click a word.
This tutorial will teach you how to control text selection on the page, how to style the selection highlight color,
and how to keep Safari happy (spoiler: use the -webkit- prefix).
What user-select does
user-select controls whether (and how) the user can select text/content with their mouse, trackpad, or
touch selection handles.
- It’s about selection, not copying. (Copy is just what people do after selecting.)
- It’s often used for UI: buttons, draggable cards, custom controls.
- It can hurt UX if used too aggressively (like disabling selection on the entire page).
.demo-area {
-webkit-user-select: auto;
user-select: auto;
}
.demo-area {
-webkit-user-select: text;
user-select: text;
}
.demo-area {
-webkit-user-select: none;
user-select: none;
}
.demo-area {
-webkit-user-select: all;
user-select: all;
}
*,
::before,
::after {
box-sizing: border-box;
}
.demo-area {
border: 3px solid #111;
padding: 16px;
font-family: ui-monospace, SFMono-Regular, monospace;
background: #f4f4f4;
border-radius: 12px;
}
.demo-area p {
margin: 0 0 12px 0;
line-height: 1.4;
}
.demo-area .chip {
display: inline-block;
padding: 6px 10px;
border: 2px solid #111;
background: #fff;
border-radius: 999px;
}
Try selecting this text. Click + drag, double-click words, or triple-click lines.
I am a tiny UI chip. Try selecting me too.
Change snippets in the playground above to switch between the common values and feel the difference immediately.
CSS user-select property basics
The property is straightforward:
user-select: auto;— browser decides (usually normal behavior)user-select: text;— selection alloweduser-select: none;— selection disableduser-select: all;— selecting any part selects the whole element
You typically apply it to the specific element you want to affect (not the whole page).
CSS user select auto
auto is the “default-ish” behavior. In most cases, it behaves like normal text selection, but it also
respects native control behavior and browser heuristics.
In other words: if you’re not sure what you need yet, auto is the “do nothing weird” setting.
.card {
-webkit-user-select: auto;
}
*,
::before,
::after {
box-sizing: border-box;
}
.card {
width: min(640px, 100%);
border: 3px solid #111;
border-radius: 16px;
padding: 16px;
background: #fff;
font-family: system-ui, -apple-system, sans-serif;
}
.card h4 {
margin: 0 0 10px 0;
font-size: 18px;
}
.card p {
margin: 0 0 10px 0;
line-height: 1.5;
}
.card code {
font-family: ui-monospace, SFMono-Regular, monospace;
background: #f2f2f2;
padding: 2px 6px;
border-radius: 6px;
border: 1px solid #ddd;
}
Selection playground
Try selecting parts of this paragraph. Then switch the radio value above.
Copy target:
INVITE-7K2M-91QX
CSS user select text
user-select: text; explicitly allows selection. This is handy if you have a component where selection is
being blocked by another rule (like a parent set to none).
Common use: disable selection on a draggable card, but re-enable it on the text area inside the card.
.draggable {
-webkit-user-select: none;
user-select: none;
}
.draggable .content {
-webkit-user-select: text;
user-select: text;
}
.draggable {
-webkit-user-select: none;
user-select: none;
}
*,
::before,
::after {
box-sizing: border-box;
}
.draggable {
width: min(680px, 100%);
border: 3px solid #111;
border-radius: 16px;
background: #f4f4f4;
padding: 12px;
font-family: system-ui, -apple-system, sans-serif;
}
.drag-handle {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 10px 12px;
border-radius: 12px;
border: 2px dashed #111;
background: #fff;
margin-bottom: 12px;
}
.drag-handle strong {
font-size: 14px;
}
.content {
padding: 14px;
background: #fff;
border-radius: 12px;
border: 2px solid #111;
line-height: 1.5;
}
.small {
opacity: 0.8;
font-size: 14px;
}
Drag handle area Try selecting text inside vs outsideSelect this paragraph. This is the “content” area where copy/paste is useful.
In the first snippet, the overall card is “non-selectable” (great for drag interactions), but the inner content is selectable (great for humans).
CSS user-select none / CSS user select disable
user-select: none; disables selection. This is perfect for “clicky UI” elements where accidental
selection feels sloppy:
- buttons
- icon controls
- drag handles
- tabs
Don’t apply user-select: none; to body or the entire
page. People will resent you because they can’t copy text, select a word to search, or use selection-based
accessibility tools.
.ui-row button,
.ui-row .tab {
-webkit-user-select: none;
user-select: none;
}
.ui-row button,
.ui-row .tab {
-webkit-user-select: text;
user-select: text;
}
*,
::before,
::after {
box-sizing: border-box;
}
.ui-row {
display: flex;
flex-wrap: wrap;
gap: 10px;
align-items: center;
border: 3px solid #111;
background: #fff;
padding: 14px;
border-radius: 16px;
font-family: system-ui, -apple-system, sans-serif;
}
.ui-row button {
border: 2px solid #111;
background: #f4f4f4;
padding: 10px 12px;
border-radius: 12px;
cursor: pointer;
font-weight: 700;
}
.ui-row .tab {
border: 2px solid #111;
background: #fff;
padding: 10px 12px;
border-radius: 999px;
}
.note {
flex-basis: 100%;
margin-top: 6px;
opacity: 0.85;
}
Tab labelTry to click-drag across the button text and the tab label.
CSS user select all
user-select: all; makes selecting any part of the element select the whole element. It’s excellent for
“copy this thing” UI such as:
- invite codes
- short tokens
- single-line commands
.copy-token {
-webkit-user-select: all;
user-select: all;
}
.copy-token {
-webkit-user-select: text;
user-select: text;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
width: min(720px, 100%);
border: 3px solid #111;
border-radius: 16px;
padding: 16px;
background: #fff;
font-family: system-ui, -apple-system, sans-serif;
}
.copy-token {
display: inline-block;
margin-top: 10px;
padding: 10px 12px;
border-radius: 12px;
border: 2px solid #111;
background: #f4f4f4;
font-family: ui-monospace, SFMono-Regular, monospace;
}
.small {
margin: 0;
opacity: 0.85;
}
Try selecting the token below. With
all, any drag selects everything.npm install my-awesome-package
Real-world patterns: combining values
Most real UI isn’t “selectable” or “not selectable” everywhere. It’s mixed:
- Disable selection on the draggable container
- Enable selection on the text region
- Use
allon copy tokens
.panel {
-webkit-user-select: none;
user-select: none;
}
.panel .body {
-webkit-user-select: text;
user-select: text;
}
.panel .copy {
-webkit-user-select: all;
user-select: all;
}
*,
::before,
::after {
box-sizing: border-box;
}
.panel {
width: min(760px, 100%);
border: 3px solid #111;
border-radius: 18px;
background: #f4f4f4;
font-family: system-ui, -apple-system, sans-serif;
}
.panel .header {
padding: 14px 16px;
border-bottom: 3px solid #111;
background: #fff;
border-radius: 16px 16px 0 0;
display: flex;
justify-content: space-between;
gap: 12px;
align-items: center;
}
.panel .header strong {
font-size: 16px;
}
.panel .header span {
opacity: 0.8;
font-size: 14px;
}
.panel .body {
padding: 16px;
line-height: 1.55;
}
.copy {
display: inline-block;
margin-top: 10px;
padding: 8px 10px;
border-radius: 12px;
border: 2px solid #111;
background: #fff;
font-family: ui-monospace, SFMono-Regular, monospace;
}
Draggable panel (pretend you drag me)Try selecting this paragraph. It should be selectable even though the panel itself isn’t.
Copy this token: RESET-4F19-ABCD
CSS user select color
This is a super common search phrase, and here’s the secret: there is no user-select-color property.
The “selection color” is styled using the ::selection pseudo-element. That’s what controls the highlight
background when the user selects text.
Styling selection with ::selection
You can usually style:
background(orbackground-color)color
Many other properties are ignored by browsers for security/consistency reasons, so keep it simple.
.demo ::selection {
background: #111;
color: #fff;
}
.demo ::selection {
background: #ffdd57;
color: #111;
}
.demo ::selection {
background: #7c3aed;
color: #fff;
}
*,
::before,
::after {
box-sizing: border-box;
}
.demo {
width: min(760px, 100%);
border: 3px solid #111;
border-radius: 16px;
padding: 16px;
background: #fff;
font-family: system-ui, -apple-system, sans-serif;
line-height: 1.6;
}
.demo h4 {
margin: 0 0 10px 0;
font-size: 18px;
}
.demo p {
margin: 0;
}
.tip {
opacity: 0.85;
font-size: 14px;
margin-top: 10px;
}
Select some text in this box
Drag to select a few words, then switch snippets to see different selection highlight colors.
Tip: selection styling usually looks best with high contrast.
If you want the selection style globally, you can target ::selection without a class (but many people
prefer scoping it to avoid surprises).
Learn more about ::selection and other pseudo-elements in the CSS Pseudo Elements Interactive Tutorial.
CSS user select safari
If you want reliable support in Safari, you should include the prefixed version:
-webkit-user-selectuser-select
In practice, you’ll often write both. The prefixed one is a “Safari seatbelt”.
.safari-safe {
-webkit-user-select: none;
user-select: none;
}
.safari-safe {
-webkit-user-select: text;
user-select: text;
}
.safari-safe {
-webkit-user-select: all;
user-select: all;
}
*,
::before,
::after {
box-sizing: border-box;
}
.safari-safe {
width: min(720px, 100%);
border: 3px solid #111;
border-radius: 16px;
padding: 16px;
background: #f4f4f4;
font-family: system-ui, -apple-system, sans-serif;
}
.safari-safe .pill {
display: inline-block;
margin-top: 10px;
padding: 8px 10px;
border-radius: 999px;
border: 2px solid #111;
background: #fff;
font-family: ui-monospace, SFMono-Regular, monospace;
}
This playground uses
-webkit-user-selectanduser-selecttogether.Select me (or try not to)
Rule of thumb: if you write user-select for UI behavior, also write
-webkit-user-select. It’s a tiny line of CSS that prevents “why is this weird on Safari?” headaches.
Common mistakes and good practices
Don’t disable selection on the whole page
Disabling selection on body (or a page wrapper) blocks everyday behaviors people rely on: copying text,
selecting an address, selecting a word to search, and some assistive workflows.
If you need non-select behavior for UI, scope it to the UI element only.
Use none for UI, and text for content
- UI regions:
user-select: none; - Content regions:
user-select: text; - Copy tokens:
user-select: all;
Remember selection styling is separate
user-select controls whether selection can happen. ::selection controls
how the selection highlight looks.
Debugging: user-select not working
- Check parents: a parent with
user-select: none;can prevent selection unless you re-enable it on the child withuser-select: text; - Safari support: add
-webkit-user-selectalongsideuser-select - Pointer interactions: some drag/gesture scripts prevent selection via JS (so the CSS may be fine, but JS is blocking)
- Is it actually text? selection behavior differs between plain text, form inputs, and custom widgets
Quick copy/paste recipes
Recipe: disable selection on buttons
Keep UI feeling crisp:
button,
.icon-button {
-webkit-user-select: none;
user-select: none;
}
*,
::before,
::after {
box-sizing: border-box;
}
.wrap {
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
border: 3px solid #111;
border-radius: 16px;
padding: 16px;
background: #fff;
font-family: system-ui, -apple-system, sans-serif;
}
button,
.icon-button {
border: 2px solid #111;
border-radius: 12px;
padding: 10px 12px;
background: #f4f4f4;
cursor: pointer;
font-weight: 700;
}
.icon-button {
width: 44px;
height: 44px;
display: flex;
justify-content: center;
align-items: center;
}
Try click-dragging across the label text.
Recipe: select-all for a copy token
Make copy-friendly snippets:
.token {
-webkit-user-select: all;
user-select: all;
}
*,
::before,
::after {
box-sizing: border-box;
}
.box {
width: min(680px, 100%);
border: 3px solid #111;
border-radius: 16px;
padding: 16px;
background: #fff;
font-family: system-ui, -apple-system, sans-serif;
}
.token {
display: inline-block;
margin-top: 10px;
padding: 10px 12px;
border: 2px solid #111;
border-radius: 12px;
background: #f4f4f4;
font-family: ui-monospace, SFMono-Regular, monospace;
}
Click-drag anywhere on the token to select everything:
curl https://example.com/setup.sh | sh
Wrap-up
You now have the full toolkit:
user-selectto control selection behavior (auto,text,none,all)::selectionto style the highlight color- Safari compatibility by always including
-webkit-user-select
If you want a simple mental model: disable selection for “controls”, allow selection for “content”, and use select-all for “copy tokens”. Your users (and your future self) will thank you.
