If you already know how to style things like block elements
and tables, and you're familiar with responsive design, then
you've already got a head start on styling forms. You can use
most of the CSS properites you are already familiar with including
Box Model properties, backgrounds, text formatting, etc.
There are some pseudo-classes that you can use specifically
for forms. Using these pseudo-classes in yor selectors
will allow you to add specific styling for input fields
when they contain invalid values or when they have the focus.
This tutorial focuses on these pseudo-classes.
Basic Form Styling
You can style your forms already using selectors and properties/values
that you've already learned. For example:
Adding borders, background/text colours, margins/padding, fonts, shadows, and
to the form elements and the various types of input elements.
Styling the label, fieldset, and legend elements with some of
the items mentioned above.
In addtion to the styling mentioned above, you may wish to
style specific types of form elements. This might seem a bit
challenging: several different kinds of inputs use the <input>
element: text fields, check boxes, radio buttons, and even
buttons. How can you style specific types of <input>
elements without cumbersome use of id selectors and
class selectors? By using attribute selectors.
If you are unfamiliar with attribute selectors, you should
go through the Attribute Selectors
The example below gives you an example of some form styling.
It includes several techniques, including the use of
attribute selectors. Feel free to fork/copy the CodePen and
play with the styles.
You've probably used forms on web pages that provide visual
cues for form validation: for example, you might have seen an icon
appear, or an input field's background or border changes colour
when the input is invalid. This is done with special CSS
pseudo-classes. You learned about pseudo classes in the
Pseudo Classes tutorial.
The pseudo classes that will be helpful in providing
visual feedback for form validation are:
:valid - this allows you
to style an element
that contains a valid input
:invalid - this allows
you to style an
element that contains an invalid input; if styling :valid, you
should put your rule with :invalid AFTER the :valid rule.
:required - this
allows you to style an element with
the required attribute (when the input is missing,
the field will be in the "invalid" state, so the :invalid rule will
apply, if it exists)
When adding the required attribute to an input,
you should also provide a text indicator that the field is
required, such as an asterisk * or the value "(required)" inside the
input's accessible <label>. This is outlined in WCAG Techniques
H90. Additionally, some screen
don't recognize the required attribute, so it's also
a good practice to add the aria-required="true"
attribute to any element that has required.
This codepen demonstrates how you might use the :required
and :invalid attributes, along with the WCAG techniques. Notice
that it also implements
H177 by providing information
values are valid for the term number field via the element's
title attribute (this meets
SC 3.3.3). The
value inside the title
attribute will show in the browser (and also read out loud by a
screen reader when the user attemps to submit
You already know how to style an element using
the :hover pseudo class. This can allow you to
create visually pleasing affects on buttons and other
In addtion, you might want to style an element
when it has the focus: when the user tabs into/on an input field or
clicked inside/on the control, this gives the element "the focus"
An element that has the focus will be the recipient of any key-presses.
For example, if a text field has the focus, any keys you press will
cause the corresponding characters to appear int he field. If
a checkbox or radio button has the focus, pressing the SPACE bar/key
will toggle (select or unselect) the control. If a button has
the focus, pressing ENTER will be equivalent to clicking the
button with the mouse.
You can style an element when it has the focus by using
the :focus or
:focus-visible pseudo classes.
:focus is used to style the appearance of
an element when it has the focus. An item recieves the focus when
the user tabs into it or on it, or when the user clicks in or
on the item. In the codepen example below, I styled elements to
have a teal border and light background when they receive the
Try tabbing between elements, and also try clicking on each
input element so you can see the focus indicators.
pseudo class is also used to style the appearance of
an element when it has the focus. The difference between :focus
and :focus-visible is that :focus-visible styles
apply only when the user needs to be informed that the element
has the focus.
For example, when the user clicks on a button with a
mouse or their finger, there is no need to indicate that the button
has the focus. However, if the user tabs to the button, they need
to know that they tabbed to the right control, so the button would
need a focus indicator. :focus-visible will only
style the button in the latter scenario (when the user tabs to the
Additionally, :focus-visible will keep the focus
indicator on an item the user clicked in/on if there is "more to do".
For example, clicking on a text field will show the focus indicator
because there is still more to do: the user will be typing
more keys to enter an input value into the field, so they need
the focus indicator to stay visible so they know which field is
being affected by the key presses. When clicking a button, there
are no more actions to perform: once the button is clicked, that's
the end of that action.
Here's the same CodePen as before, but using :focus-visible instead
of :focus (also, in order to prevent form submission while you try
out the example, I changed the submit button to a generic button,
but the demo would still work in a real form with an actual submit
button). Again, try tabbing vs clicking on the various elements
to see the difference in behaviour. Notice how tabbing to each
element shows the indicator, but clicking on the radio buttons or
the submit (generic) button does not cause the focus indicator to
appear. Clicking on the text fields does show the focus indicator
because there are still keys to press while the field has the focus.
Items with low contrast are difficult or impossible to see for low
For focusable items where the creator of the page has styled
focusable elements, the 3:1 contrast ratio applies to:
Where the focus indicator is outside the element (e.g. an outline),
the focus indicator must have a 3:1 contrast with the background
of the element's container.
Where the focus indicator is inside the element (e.g. an
inner outline around the text of the element), the 3:1 constrast
applies to the colour of the indicator and the element's background.
There are several specific details about focusable elements
in the criteria's documentation. You can see in the two CodePen
examples for :focus and :focus-visible that I used colours that
met these constrast minimums.
SC 2.4.7 states that when an item receives the focus, there must
be a focus indicator (e.g. a visible border, a vertical cursor or
insertion point, or other visual cue) if that item if it can be
activated or affected by the keyboard (e.g. if it's something that
can be clicked by pressing ENTER, receive input via key presses or
toggling with the SPACE key, etc.).
It also states that the focus
indicator can't be time-sensitive (e.g. it must stay there until the
user moves the focus elsewhere, the focus indicator can't disappear
after a certain amount of time).
This assist users who navigate with a keyboard by indicating which
field is affected by keypresses, and also users with cognitive
issues such as limited attention span, memory issues, and issues with
performing tasks by making it clear where to find the control that
currently has the focus.
Techniques you can use to meet 2.4.7 include:
G149 - only use HTML elements that browsers recognize
as a focusable element. For example, use buttons for clickable
elements that trigger actions, don't use images instead of buttons
because browsers don't normally give images the focus when a user
tabs around on the screen.
G165 - use the system's default focus indicator. Many
users customize the focus indicators in their operating system's
settings or the settings of their assistive device/software
to suit their needs.
G195 - enchance the default focus indicators by
modifying the thickness of the line, contrasting colours (see
SC 1.4.11 below), glow, etc. This can be done by following
technique C15 or C40, mentioned next.
C15 - use CSS to change the appearance of
elements that receive the focus (which is what the :focus
pseudo classes are for). For example, changing their background colour
or text colour.
C40 - on sites that have a lot of colours, especially
of the background behind focusable elements, use 2 contrasting colours
to indicate that an item has the focus. For example, an element could
have a red outline with a grey drop-shadow. This allows you to create
a focus indicator for different backgrounds without having to
write many different rules for the different elements. The two
contrasting colours should have a 9:1 contrast ratio and at least
one of the two colours should have a 3:1 contrast ratio with the
You can see in both the :focus and :focus-visible examples I
used technqies G149, G195, and C15 by setting a thicker outline
around the elements in a colour that contrasted the rest of the
element and the surrounding colours.
SC 2.4.13 (Focus Appearance) is a combination
of SC 2.4.7 and 1.4.11 that was added to WCAG 2.2 that has stricter
requirements to meet AAA-level compliance. To meet this criteria:
The focus indicator must be a minimum perimeter of 2 pixels.
Perimeter in this context is defined as the boundary
of the element or the boundary of the rectangular space taken up
by the element in the browser viewport.
The pixels that the focus indicator uses must have a minumum 3:1
contrast ration between the focused and unfocused state.
There are a couple of exceptions that are relevant if the
developer didn't style the focus indicator or the element's background
colour(they're using the browser defaults).
You can see in both the :focus and :focus-visible examples from
earlier that I met this success criteria by setting a thicker outline
of .2em (my base font was 20px) and in contrasting colours: my outline
and foreground colour had a contrast ratio of 3.25:1 and
the outline colour had a contrast ratio of 3.8:1 with the background
of the <div> that contained the label/input.
Styling Active Elements
You can also style controls that are active:
An active control is in the process of being clicked, so this
generally only applies to links and buttons. This can be done
by using the :active pseudo class. An example of how you
might use :active to style a button is shown in the following
You can style items when they're in the checked or selected
state by using the :checked pseudo class. This allows you
to add styling to checkboxes and radio buttons when they have
been checked/selected, and to <option> elements of a <select>
list when the <option> has been selected. The browser already
has default styling for these states, but you can customize
the appearance using the :checked pseudo class.
Here's a simple CodePen that shows an example of how you might
style :checked elements:
Placeholders are text contents that are often added to
text input fields to add additional information about the
required or expected inputs, or to provide a field label when
there isn't enough screen real estate for an actual <label>
element. For example:
<label for="fname">First Name:
<input type="text" id="fname" name="firstname"
placeholder="first or given name">
You can use the :placeholder-shown pseudo class
to style the appearance of an element when it contains
placeholder textm and you can use the
::placeholder pseudo element
to style the actual placeholder text. The CodePen below shows
an example of styling both the :placeholder-shown
and ::placeholder pseudo selectors: