Standardizing input elements across browsers

Sue Anna Joe
Zoosk Engineering
Published in
5 min readNov 16, 2019

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.

Native inputs with no styles

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 on input. This will apply the color to both enabled and disabled filled text. If you want a different disabled filled text color, you have to set color on input:disabled.
  • As expected you can change the placeholder text color by customizing the color property on input::placeholder. This will apply the color to enabled and disabled placeholder text. If you want to a different color on disabled placeholder text, use input: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 to input affects all placeholder and filled text (enabled and disabled fields). If you want a different color for your placeholder text, set the color property on input::placeholder.
  • Applying a custom color to input:disabled affects disabled placeholder and filled text.
  • FF applies 50% opacity to enabled and disabled placeholder text. To normalize those, add opacity: 1 to input::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 on input 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 use purple, 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 the input: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 on input::placeholder to change the color of all placeholder text or 2) use the -webkit-text-fill-color property on input: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 on input 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 on input normalizes the opacity of the entire element including placeholder and filled text. You can also set opacity on just input: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 on input:disabled applies the color to disabled placeholder and filled text.
  • Setting color on input 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.

--

--