Update advanced form styling for accent-color, file pickers and number inputs - #45453
Conversation
…r inputs Addresses three issues on the Advanced form styling page, which a maintainer asked to be fixed together. Adds an accent-color section for checkboxes and radio buttons. The page went straight to `appearance: none` and rebuilding the control by hand, with no mention of the one-property option that covers the common case of only wanting a different color. Corrects the claim that the file picker button is "completely unstylable". It has been stylable with ::file-selector-button for some years. The label technique the page already described is kept, since it is still the way to control the text beside the button, which CSS cannot reach. Replaces the note suggesting `<input type="tel">` as a way to avoid the number spinner. Switching type to lose a spinner changes the meaning of the field and what the browser validates. Recommends `inputmode="numeric"` with a pattern attribute instead, matching the guidance already on the `<input type="number">` page. Also notes on Styling web forms that the file picker button is stylable, since that page lists `<input type="file">` among the controls whose internals CSS cannot reach.
|
Preview URLs (2 pages)
External URLs (1)URL:
(comment last updated: 2026-09-03 12:11:15) |
chrisdavidmills
left a comment
There was a problem hiding this comment.
Thanks, @natiD1; this seems like a reasonable effort. I've made several suggestions for improving the text and improving the continuity with what's already there.
| } | ||
| ``` | ||
|
|
||
| ### Styling checkboxes and radio buttons using `accent-color` |
There was a problem hiding this comment.
| ### Styling checkboxes and radio buttons using `accent-color` | |
| ### Setting form control color tints using `accent-color` |
Because it doesn't only affect checkboxes and radios. It affects others too.
|
|
||
| ### Styling checkboxes and radio buttons using `accent-color` | ||
|
|
||
| If the only thing you want to change is the color, {{cssxref("accent-color")}} will do it without taking the control apart. The browser carries on drawing the checkbox or radio button itself, and tints it: |
There was a problem hiding this comment.
| If the only thing you want to change is the color, {{cssxref("accent-color")}} will do it without taking the control apart. The browser carries on drawing the checkbox or radio button itself, and tints it: | |
| If you only want to style the primary tint color of checkboxes, radio buttons, or range sliders, the {{cssxref("accent-color")}} will do it without requiring `appearance: none`. This is useful for basic styling cases, as the controls maintain their OS-level styling, but with an altered main color. |
|
|
||
| If the only thing you want to change is the color, {{cssxref("accent-color")}} will do it without taking the control apart. The browser carries on drawing the checkbox or radio button itself, and tints it: | ||
|
|
||
| ```html live-sample___checkboxes-accent-color |
There was a problem hiding this comment.
Nitpick: change the identifier to accent-color, since the example includes a radio button and a checkbox.
| </form> | ||
| ``` | ||
|
|
||
| ```css live-sample___checkboxes-accent-color |
There was a problem hiding this comment.
again, "accent-color"?
|
|
||
| {{EmbedLiveSample("checkboxes-accent-color", '100%', 160)}} | ||
|
|
||
| Because the control keeps its native appearance, it goes on following platform conventions — including forced-colors modes — with no further work on your part. Reach for the `appearance: none` approach below when you need to change more than the color. |
There was a problem hiding this comment.
| Because the control keeps its native appearance, it goes on following platform conventions — including forced-colors modes — with no further work on your part. Reach for the `appearance: none` approach below when you need to change more than the color. | |
| Because the control keeps its native appearance, it follows platform conventions — including forced-colors modes — with no further work on your part. In addition, the browser automatically chooses a complementary secondary color with enough contrast to the `accent-color` to keep the control accessible. Play with the above live example and set some light and dark `accent-color` values to see the effects. |
|
|
||
| > [!NOTE] | ||
| > It is worth mentioning [`<input type="number">`](/en-US/docs/Web/HTML/Reference/Elements/input/number) here too — this also has a spinner that you can use to increment/decrement values, so potentially suffers from the same problem. However, in the case of the `number` type the data being collected is simpler, and it is easy to just use a `tel` input type instead, which has the appearance of `text`, but displays the numeric keypad in devices with touch keyboards. | ||
| > [`<input type="number">`](/en-US/docs/Web/HTML/Reference/Elements/input/number) has a spinner too, and its internal parts are no easier to style. If the spinner is the part you want to be rid of, don't reach for `tel`: that changes what the field means, and the browser will validate it as a telephone number rather than as a number. Use [`<input type="text">`](/en-US/docs/Web/HTML/Reference/Elements/input/text) with [`inputmode="numeric"`](/en-US/docs/Web/HTML/Reference/Global_attributes/inputmode) and a [`pattern`](/en-US/docs/Web/HTML/Reference/Attributes/pattern) attribute instead. You still get the numeric keypad on devices with touch keyboards, without the spinner and without claiming the value is a phone number. See [Accessibility](/en-US/docs/Web/HTML/Reference/Elements/input/number#accessibility) on the `<input type="number">` page. |
There was a problem hiding this comment.
| > [`<input type="number">`](/en-US/docs/Web/HTML/Reference/Elements/input/number) has a spinner too, and its internal parts are no easier to style. If the spinner is the part you want to be rid of, don't reach for `tel`: that changes what the field means, and the browser will validate it as a telephone number rather than as a number. Use [`<input type="text">`](/en-US/docs/Web/HTML/Reference/Elements/input/text) with [`inputmode="numeric"`](/en-US/docs/Web/HTML/Reference/Global_attributes/inputmode) and a [`pattern`](/en-US/docs/Web/HTML/Reference/Attributes/pattern) attribute instead. You still get the numeric keypad on devices with touch keyboards, without the spinner and without claiming the value is a phone number. See [Accessibility](/en-US/docs/Web/HTML/Reference/Elements/input/number#accessibility) on the `<input type="number">` page. | |
| > [`<input type="number">`](/en-US/docs/Web/HTML/Reference/Elements/input/number) has a spinner too, and its internal parts are no easier to style. If you want to remove the spinner, use [`<input type="text">`](/en-US/docs/Web/HTML/Reference/Elements/input/text) with [`inputmode="numeric"`](/en-US/docs/Web/HTML/Reference/Global_attributes/inputmode) set to display a numeric keypad on devices with touch keyboards and a [`pattern`](/en-US/docs/Web/HTML/Reference/Attributes/pattern) attribute that limits input values to a number. See also [`<input type="number">` > Accessibility](/en-US/docs/Web/HTML/Reference/Elements/input/number#accessibility). |
| @@ -595,9 +630,21 @@ However, a custom solution is the only way to get anything significantly differe | |||
|
|
|||
| Inputs of type file are generally OK — as you saw in our example, it is fairly easy to create something that fits in OK with the rest of the page — the output line that is part of the control will inherit the parent font if you tell the input to do so, and you can style the custom list of file names and sizes in any way you want; we created it after all. | |||
There was a problem hiding this comment.
| Inputs of type file are generally OK — as you saw in our example, it is fairly easy to create something that fits in OK with the rest of the page — the output line that is part of the control will inherit the parent font if you tell the input to do so, and you can style the custom list of file names and sizes in any way you want; we created it after all. | |
| Inputs of type file are generally OK — it is fairly easy to create something that fits in OK with the rest of the page. The output line that is part of the control will inherit the parent font if you tell the input to do so, and you can style the custom list of file names and sizes in any way you want. |
| The button you press to open the file picker can be styled with the {{cssxref("::file-selector-button")}} pseudo-element, which accepts the same properties as any other button: | ||
|
|
||
| ```css | ||
| input[type="file"]::file-selector-button { |
There was a problem hiding this comment.
It would be good for you to show this as a live example, so people can see the effect of the declaration you've shown. Also, the way it is written, people might think this is part of the live example further down, which is not the case.
| } | ||
| ``` | ||
|
|
||
| What you can't reach this way is the text beside the button — the "no file chosen" message, and the name of the file once one has been picked. The browser generates that text and doesn't expose it to CSS. |
There was a problem hiding this comment.
| What you can't reach this way is the text beside the button — the "no file chosen" message, and the name of the file once one has been picked. The browser generates that text and doesn't expose it to CSS. | |
| You can't style the text beside the button — the "no file chosen" message — or the displayed filename once chosen. The browser generates that text and doesn't expose it to CSS. To work around this problem, you can use the control's label and the fact that clicking the label activates the control. | |
| You could hide the actual form input using something like this: |
| What you can't reach this way is the text beside the button — the "no file chosen" message, and the name of the file once one has been picked. The browser generates that text and doesn't expose it to CSS. | ||
|
|
||
| One way around this is to take advantage of the fact that if you have a label associated with a form control, clicking the label will activate the control. So you could hide the actual form input using something like this: | ||
| If you need control over that part as well, you can take advantage of the fact that if you have a label associated with a form control, clicking the label will activate the control. So you could hide the actual form input using something like this: |
There was a problem hiding this comment.
Delete this line, as I merged it with the paragraph above.
| If you need control over that part as well, you can take advantage of the fact that if you have a label associated with a form control, clicking the label will activate the control. So you could hide the actual form input using something like this: |
Renames the accent-color heading to cover form controls generally rather than just checkboxes and radio buttons, since the property also tints range sliders, and renames the live sample to match. Adds a range slider to that sample so it demonstrates the three controls the text now names. Rewrites the accent-color intro and closing paragraphs, the opening of the appearance section, the number input note and the file input opening, following the suggestions on the pull request. Turns the ::file-selector-button snippet into a live example of its own, so the declaration can be seen taking effect and is no longer mistakable for part of the styled file picker example further down.
chrisdavidmills
left a comment
There was a problem hiding this comment.
This all looks good; thanks, @natiD1!
Description
Three fixes to the Advanced form styling page, which @Josh-Cena asked to be handled together in #36090, #24304 and #42946, plus one related note on Styling web forms.
accent-color(Advanced form styling should mention accent-color #24304): adds a short section covering the color-only case. The page went straight toappearance: noneand rebuilding the control by hand, with no mention of the one-property option that covers the common case of only wanting a different color.::file-selector-buttonfor some years. The existing label technique is kept, since it is still the way to control the text beside the button, which CSS cannot reach.<input type="tel">as a way to avoid the spinner.Motivation
All three are cases where the page tells a learner something that is no longer true, or steers them toward a workaround with a cost the page doesn't mention.
The
telsuggestion is the one I would single out. Swapping the input type to get rid of a spinner changes what the field means and what the browser validates, which is a lot to trade for an appearance problem. The replacement recommendsinputmode="numeric"with apatternattribute, which is what the Accessibility section of<input type="number">already recommends, so this brings the Learn page in line with the reference page rather than introducing new advice.Additional details
accent-colorsection: I put it immediately before theappearanceone, so a reader meets the cheaper option first. That does mean the heading sits under the## appearance: controlling OS-level stylingparent, which is a slightly awkward fit. I can move it out to its own##section, or after theappearanceone, if you prefer.<input type="file">under "having internals that can't be styled in CSS alone". Rather than recategorizing it, given the button is stylable but the file name text still isn't, I added a note in the style of the existing<select>one. Let me know if you would rather handle that page separately.Related issues and pull requests
Fixes #24304
Fixes #36090
Fixes #42946