Standardizing input elements across browsers
In the last 16 years I’ve never had a project that required custom styles for disabled inputs. I know this because when I worked on such a project last week I was pulling my hair out. Most of us in the business know that browsers like to render inputs in their own ways. My cross-browser testing showed that when you throw the disabled state into the mix, you can get a really big headache.
I created a CodePen demo of plain inputs to get screenshots of these cross-browser differences. The only significant custom style I added was a larger font-size
to make the placeholder and filled text (value
) more readable.
As I iterated the changes for my real-life project, I discovered some of the funny things going on with inputs, and I used some browser-specific techniques to fix them, though not all required vendor prefixes. Before I get to those solutions, it’s helpful to see a second CodePen demo with some made-up style requirements:
- Enabled placeholder text color:
cornflowerblue
- Enabled input filled text color:
purple
- Disabled placeholder text color:
cornflowerblue
- Disabled filled text color:
purple
- Disabled input background:
lightgray
- All inputs:
1px solid black
border
For this demo I created the styles first in Chrome. I used what I consider CSS techniques that should work consistently in these browsers (but don’t). Below are the results.
The browsers sort of rendered as expected, though at this point I purposefully didn’t include vendor-prefixed solutions for IE and Edge. Still, we have some slight variations. To provide a little insight on what’s going on, below are some observations I made when I worked on my real-life project. I also included snippets of the styles needed to meet the CodePen demo’s requirements on a per section basis.
WebKit browsers
In Chrome and Safari (desktop and iOS), Android Chrome, and Samsung Internet, setting color
on input
affects filled text for both enabled and disabled inputs.
Chrome (desktop version 71 and mobile version 70 on Android 7.1) and Samsung Internet (version 8.2 on Android 7.1)
- As expected you can change an input’s filled text color by customizing the
color
property oninput
. This will apply the color to both enabled and disabled filled text. If you want a different disabled filled text color, you have to setcolor
oninput:disabled
. - As expected you can change the placeholder text color by customizing the
color
property oninput::placeholder
. This will apply the color to enabled and disabled placeholder text. If you want to a different color on disabled placeholder text, useinput:disabled::placeholder
.
// Styles needed to meet demo requirementsinput {
border: 1px solid black;
color: purple;
}input:disabled {
background: lightgray;
}input::placeholder {
color: cornflowerblue;
}
Firefox (desktop version 65 and mobile version 65 on Android 7.1)
- Applying a custom
color
value toinput
affects all placeholder and filled text (enabled and disabled fields). If you want a different color for your placeholder text, set thecolor
property oninput::placeholder
. - Applying a custom
color
toinput:disabled
affects disabled placeholder and filled text. - FF applies 50% opacity to enabled and disabled placeholder text. To normalize those, add
opacity: 1
toinput::placeholder
.
// Styles needed to meet demo requirementsinput {
border: 1px solid black;
color: purple;
}input:disabled {
background: lightgray;
}input::placeholder {
color: cornflowerblue;
opacity: 1;
}
Safari (desktop version 11.1)
- Like Chrome, Safari will take a custom
color
oninput
and apply it to enabled and disabled filled text. Some color values, however, will render as a different hue in disabled inputs. For example, if you usepurple
, the disabled filled text will look more like fuchsia. - If you want the enabled and disabled filled text colors to match, assign your color to
input
. Then create a block with theinput:disabled
selector and use the-webkit-text-fill-color
property with the same color. This will, however, apply the color to the disabled input’s placeholder text. If this is not desirable, you have two options: 1) use the-webkit-text-fill-color
property oninput::placeholder
to change the color of all placeholder text or 2) use the-webkit-text-fill-color
property oninput:disabled::placeholder
for specific targeting.
// Styles needed to meet demo requirementsinput {
border: 1px solid black;
color: purple;
}input:disabled {
background: lightgray;
-webkit-text-fill-color: purple; // Only needed if you want all filled text to have the same color and you happen to pick a color that doesn't render correctly in a disabled input. FYI This will also apply to disabled filled and placeholder text in Chrome.
}input::placeholder {
-webkit-text-fill-color: cornflowerblue; // Changes all placeholder color
}
Chrome and Safari (iOS 12)
- Like their desktop counterparts these browsers will take a custom
color
oninput
and apply it to enabled and disabled filled text. They also have the same inconsistent hue issue noted above for desktop Safari. The solution is the same. - Disabled inputs have a 40% opacity. Setting
opacity: 1
oninput
normalizes the opacity of the entire element including placeholder and filled text. You can also setopacity
on justinput:disabled
for the same effect.
// Styles needed to meet demo requirementsinput {
border: 1px solid black;
color: purple;
}input:disabled {
background: lightgray;
-webkit-text-fill-color: purple;
opacity: 1;
}input::placeholder {
-webkit-text-fill-color: cornflowerblue;
}
IE 11
- Setting
color
oninput:disabled
applies the color to disabled placeholder and filled text. - Setting
color
oninput
applies the color to all filled and placeholder texts, enabled and disabled. You can use a variety of selectors to override this and customize your text colors:
input:-ms-input-placeholder {...}
input:disabled {...}
input:disabled:-ms-input-placeholder {...}
input:disabled:not(:-ms-input-placeholder) {...}// Styles needed to meet requirementsinput {
border: 1px solid black;
color: purple;
}input:disabled {
background: lightgray;
}input:-ms-input-placeholder {
color: cornflowerblue;
}
Edge 17
If you want to customize placeholder text, Edge requires the input::-webkit-input-placeholder
selector.
// Styles needed to meet requirementsinput {
border: 1px solid black;
color: purple;
}input:disabled {
background: lightgray;
}input::-webkit-input-placeholder {
color: cornflowerblue;
}
Closing
I have a third CodePen demo with all these styles consolidated. If you view it in the browsers mentioned here, you’ll see much more consistency. You don’t have to use all these workarounds; it depends on what your requirements are. Also, if you need to change Chrome’s pre-filled input styles, check out Bobby Westberg’s solution. Hopefully with all this information you’ll have an easy time customizing placeholder and filled texts for enabled and disabled inputs.