0

How to prevent user-selection / highlighting of an <input>?

This:

input { 
  user-select: none;
}
<input type="number" value="123" />

and the methods from How to disable text selection highlighting and CSS disable text selection and don't work on an input.

Note: if possible, I don't want to put the input on disabled mode.

Basj
  • 41,386
  • 99
  • 383
  • 673
  • does the input need to be of type `number` ? – ThS Oct 04 '22 at 13:40
  • @ths Yes indeed. – Basj Oct 04 '22 at 13:42
  • Am afraid selection related method/events are not supported by `number` inputs. – ThS Oct 04 '22 at 13:44
  • This can be fought with a transparent selection color: `input::selection { background: transparent; }` `input::-moz-selection { background: transparent; }` – Daniel Bednář Oct 04 '22 at 13:46
  • @ths I tried with `type="text"` and it seems similar: `user-select: none;` doesn't work. Is it the same for you? – Basj Oct 04 '22 at 13:47
  • @Basj what I said is *"selection related method/events are not supported"* I wasn't speaking of `CSS`. A workaround is to use a `text` input which will allow you to prevent selection but you'll need to validate user input to only allow numbers. – ThS Oct 04 '22 at 13:49
  • @DanielBednář I'll still be able to select and copy from that input... – ThS Oct 04 '22 at 13:50
  • @ths My ultimate goal is to prevent selection and that further keystrokes are deleting/replacing the selected characters. – Basj Oct 04 '22 at 13:51
  • @Basj There's a huge difference between preventing selection and preventing deleting/changing the input's value. Which one you need ? – ThS Oct 04 '22 at 13:52
  • @ths I need both, but if not possible, one of them would be already something. – Basj Oct 04 '22 at 13:58
  • @Basj One last question, do you allow users to change the value inside that input ? – ThS Oct 04 '22 at 14:00
  • @ths When the user clicks on the input, a touchscreen numpad popup opens, and this numpad modifies the input's value, still using the input's validation, etc. But I want to prevent selection etc. – Basj Oct 04 '22 at 14:03
  • @Basj please check this [answer](https://stackoverflow.com/questions/29221991/prevent-select-on-input-text-field#answer-29222158) it might help you. – ThS Oct 04 '22 at 14:04
  • @ths we can still see the selection during the drap n drop. For now, I'll just do a `evt.preventDefault();` after opening the numpad popup when the user clicks on the `input`. It seems to work. – Basj Oct 04 '22 at 14:07
  • @Basj actually that the farther we can get until some new events come to light that allow us to have more control like [`this EXPERIMLENTAL event`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/selectionchange_event). – ThS Oct 04 '22 at 14:10

5 Answers5

0

You can hide the selection like this:

input::selection {
    background-color:transparent;
}

The illusion will be broken if the user drags the text after selecting it, but I don't think there's any other way to do it.

(Why would you want to do this though)?

  • 1
    I am still able to select so your attempt doesn't solve the OP's issue. – ThS Oct 04 '22 at 14:00
  • @ths That's true, but I don't think there's any other way to do it aside from making a custom input through javascript or something. –  Oct 04 '22 at 14:02
  • There are, but we should stick to the OP's requirements. – ThS Oct 04 '22 at 14:03
0

You could try to (almost instantly) remove the selection when someone selects something inside the input element with .getSelection().removeAllRanges();.

It is still possible to copy the text if someone is quick.

$("input").select(function() {
    window.getSelection().removeAllRanges();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="number" value="123">

You can improve this by making it look like text is not selectable (see Samuel's answer), I added it into an extra code snippet:

$("input").select(function() {
        window.getSelection().removeAllRanges();
});
input::selection {
    background-color:transparent;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="number" value="123">

After all of this you can also make it imposible for the user to copy anything inside an input field by adding onCopy="return false" to the input field. (It is still selectable but not possible to copy).

<input type="number" value="123" onselectstart="return false" oncopy="return false;" />

You might only want to use 1 or a combination of 2 of those things inside your project. Combine the things you need and you can make an unselectable/uncopy-able input field.

You can also disable cutting/pasting or right clicking according to this article.

Jeremy
  • 1,384
  • 3
  • 10
  • 24
0

Reading your requirements, it seems you'd probably fulfil them best by not using user-facing number input at all, or more precisely, progressively enhance it to some "ticker" structure.

Such progressively enhanced number input without possibility to select the value could be something like:

<form onsubmit="alert('Value is: ' + this.v.value); return false">
  <label for="o">Value: </label>
  <!-- Displays the value: -->
  <output id="o" for="plus minus"
    style="min-width: 2em;
      display: inline-block;
      text-align: right; border: 1px solid;
      padding-inline: .5em;
      user-select: none;
      /* user-select: none; is probably not necessary here anymore
         since keyboard input here does not affect the value
      */
">0</output>
  <!-- Holds actual value: -->
  <input name="v" type="hidden" value="0" onchange="o.value=value">
  <!-- Controls: -->
  <button id="plus" type="button" aria-label="Increase value"
  onclick="v.value=Number(v.value)+1;v.onchange()"
  >+</button>
  <button id="minus" type="button" aria-label="Decrease value"
  onclick="v.value=Number(v.value)-1;v.onchange()"
  >-</button>
  <hr>
  <input type="submit">
</form>

(Again, this structure is for demonstration only, underlying element should be regular number input. Both should work with screen readers and other assistive technologies, but haven't verified this one ATM.)

myf
  • 9,874
  • 2
  • 37
  • 49
0

This seems to work, as a first approximation:

input { 
    pointer-events: none;
}
<input type="number" value="123" />
Basj
  • 41,386
  • 99
  • 383
  • 673
0

This works if you still want pointer events:

Vanilla

<style>
input::selection {
  background-color: transparent;
}
</style>

<input 
  type="number"
  oncopy="return false"
  oncut="return false"
  onpaste="return false"
/>

React with Styled Components

import styled from 'styled-components';

const ScInput = styled.input`
  &::selection {
    background-color: transparent;
  }
`;

const Input = () => (
  <Input
    onCopy={(e) => e.preventDefault()}
    onCut={(e) => e.preventDefault()}
    onPaste={(e) => e.preventDefault()}
  />
);

export default Input;

Disables copy/cut/paste functionality of an input and makes the selection transparent.

Chris Pavs
  • 85
  • 5