Styling
It’s a common practice to indicate error states with styles, usually with red outlines, red error messages etc.
Input border
input-validity
is adding data-dirty
attribute after first submit attempt, but it’s recommended to use :invalid
CSS pseudo-class to add error styles when input is invalid.
Try to submit empty field and then add some value. Error styles will change to default automatically.
Styling error message
input-validity
doesn’t control rendering of error message DOM element - it only update it’s content.
Let’s add some styles to our error message.
<form action="/submit"> <input type="text" required validation-message="#error" /> <div id="error" class="error-box"></div> <button>submit</button></form>
input[data-dirty]:invalid { border-color: #e60202; outline: #e60202 solid 1px;}
.error-box { padding: 0.2rem 0.5rem; border: 1px solid #e60202; border-radius: 3px; background: #ffc4c4;}
As you can see our error message element is visible even without any actual message. It’s recommended to use :empty
CSS pseudo-class to handle such situations. No need for conditional rendering, adding or removing DOM elements, no templating.
<form action="/submit"> <input type="text" required validation-message="#error" /> <div id="error" class="error-box"></div> <button>submit</button></form>
input[data-dirty]:invalid { border-color: #e60202; outline: #e60202 solid 1px;}
.error-box { padding: 0.2rem 0.5rem; border: 1px solid #e60202; border-radius: 3px; background: #ffc4c4;}
.error-box:empty { display: none;}
Styling parent element
When you want to style parent element, for example indicate an error on the parent element such as card, fields group etc, it’s again recommended to just use CSS with :has()
. This will reduce need for client side javascript, conditional rendering or class manipulation.
<form action="/submit"> <fieldset> <label>Provide any value</label> <input type="text" required validation-message="#error" /> <div id="error" class="error-box"></div> </fieldset> <button>submit</button></form>
input[data-dirty]:invalid { border-color: #e60202; outline: #e60202 solid 1px;}
fieldset { background: #eee; border-radius: 3px; border: 2px solid transparent;}
fieldset:has([data-dirty]:invalid) { border-color: #e60202;}
.error-box { color: #e60202;}
.error-box:empty { display: none;}
TailwindCSS
input-validity
pairs nicely with TailwindCSS. Here’s above example styled with Tailwind
<form action="/submit" class="m-2"> <fieldset class="p-4 bg-gray-100 mb-2 rounded border-2 border-transparent [&:has([data-dirty]:invalid)]:border-red-600"> <label>Provide any value</label> <input type="text" required validation-message="#error" class="mb-2 border-2 border-gray-200 data-[dirty]:invalid:border-red-600 data-[dirty]:invalid:focus:outline-red-600" /> <div id="error" class="empty:hidden text-red-600"></div> </fieldset> <button class="bg-blue-600 text-white py-1 px-2 rounded"> submit </button></form>