- Because
<input type="checkbox" />
and <input type="radio" />
(and most other elements) are inherently read-only.
- Unlike an
<input type="text" />
or <input type="date" />
, when you interact with (i.e. toggle) a checkbox or radio button you are not changing its value
, you are changing its checked
state.
- Yes, I agree it's counter-intuitive.
Consequently...
- You should not apply the
<input readonly
attribute to a radio
or checkbox
for any purpose.
- Because it won't do anything useful.
- You should not define a CSS selector that uses the
:read-only
pseudo-class to select <input>
elements that have an explicit HTML <input readonly
attribute set.
From the current WHATWG HTML specification (emphasis mine, especially the last point):
https://html.spec.whatwg.org/multipage/semantics-other.html#selector-read-only
The :read-write
pseudo-class must match any element falling into one of the following categories, which for the purposes of Selectors are thus considered user-alterable: [SELECTORS]
<input>
elements to which the <input readonly
attribute applies, and that are mutable (i.e. that do not have the <input readonly
attribute specified and that are not <input disabled
).
<textarea>
elements that do not have a <textarea readonly
attribute, and that are not <textarea disabled
.
- elements that are editing hosts or editable and are neither
<input>
elements nor <textarea>
elements.
- The
:read-only
pseudo-class must match all other HTML elements.
Now, if you want a "read-only checkbox/radio" then you don't have too many good options, unfortunately; instead you have a mix of terrible options and barely-adequate ones...:
If you want to use the :read-only
pseudo-class on all input
elements except radio and checkboxes then you need to think carefully (and test it too, using variations on document.querySeletorAll("input:read-only")
in your browser's console!)
I recommend that you do not apply any styles using selectors for input
elements without also explicitly specifying the [type=""]
attribute selector - this is because styles with a selector like "input
" (without any attribute-selectors) will be applied to future HTML input elements that we don't know about yet and could be introduced at any point in the near-future, and maybe next week Google Chrome adds a new <input type="human-dna-sample" />
or Microsoft adds <input type="clippy" />
to a particularly retro edition of their Edge browser - so you definitely don't want a :read-only
style applied to those elements until you at least know how it will look and work - and so the browser will use its default/native styling which won't violate your users/visitor's expectations if they happen to come across it on your website at some point.
...so it means you need to write out rules for every known <input type="...">
as repetitive input[type=""]
style rules, and now you might wonder if there were any pseudo-classes for input
elements based on their default native appearance because a lot of them sure do look share similar, if not identical, native appearance and visual-semantics (and shadow DOM structure, if applicable) - for example in desktop Chrome the input types text
, password
, email
, search
, url
, tel
and more are all clearly built around the same native textbox widget, so there surely must be a pseudo-class for different input "kinds", right? Something like input:textbox-kind
for text
, password
, etc and input:checkbox-kind
for checkbox
and radio
- unfortunately such a thing doesn't exist and if introduced tomorrow the W3C's CSS committee probably wouldn't approve it for a few more years at least - so until then we need to explicitly enumerate every input[type=""]
that we know about so that we can accurately anticipate how browsers will render them with our type=""
-specific style rules instead of throwing everything as input {}
and seeing what sticks.
...fortunately the list isn't too long, so I just wrote the rules out just now:
Feel free to copy + paste this; it's hardly even copyrightable. And I want to see how far this spreads across the Internet in my lifetime.
At the bottom is a CSS selector that will select only <input
elements that are from the future by using an exhaustive set of :not([type="..."])
selectors, as well as not matching input
elements with an empty type=""
attribute or missing one entirely.
/* Textbox-kind: */
input[type="text"]:read-only,
input[type="password"]:read-only,
input[type="search"]:read-only,
input[type="tel"]:read-only,
input[type="url"]:read-only,
input[type="email"]:read-only,
input[type="number"]:read-only {
background-color: #ccc;
cursor: 'not-allowed';
}
/* Date/time pickers: */
input[type="date"]:read-only,
input[type="datetime-local"]:read-only,
input[type="time"]:read-only,
input[type="week"]:read-only,
input[type="month"]:read-only {
background-color: #ccc;
cursor: 'not-allowed';
}
/* Button-kind (these are all practically obsolete now btw, as the <button> element is far, far, far superior in every way) */
input[type="button"]:disabled,
input[type="reset"]:disabled,
input[type="submit"]:disabled,
input[type="image"]:disabled {
background-color: #ccc;
border: 1px outset #666;
cursor: 'not-allowed';
color: #666;
text-shadow: 0 1px rgba(255,255,255,0.2);
}
/* Checkbox-kind (Don't use `:read-only` with these): */
input[type="checkbox"]:disabled,
input[type="radio"]:disabled {
/* I'm not setting any properties here because it's impossible to effectively style these elements without resorting to image-replacements using the `:checked` state in selectors for their parent or adjacent `<label>` or ::before/::after` of other proximate elements. */
}
/* Weird-stuff-kind: */
input[type="color"]:read-only,
input[type="file"]:read-only,
input[type="hidden"]:read-only,
input[type="range"]:read-only {
/* Again, due to differences in how different browsers and platforms display (and consequently style) these inputs I don't think it's worth doing anything. */
}
/* If you **really** want to select _future_ <input> elements in-advance... do this: */
input[type]:not([type="text"]):not([type="password"]):not([type="search"]):not([type="tel"]):not([type="url"]):not([type="email"]):not([type="number"]):not([type="date"]):not([type="datetime-local"]):not([type="time"]):not([type="week"]):not([type="month"]):not([type="button"]):not([type="reset"]):not([type="submit"]):not([type="image"]):not([type="checkbox"]):not([type="radio"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="range"]) {
}