Front-end elective,
3rd Semester
But first...
by Jonas Holbech
But first...
by Jonas Holbech
But first...
by Jonas Holbech
Search for a topic of interest...
A better user experience
HTML forms
Frontend elective, 3rd SEM
Search for a topic of interest...
Last time
Today
Mostly HTML
Mostly CSS
A CSS pseudo-class is a keyword added to a selector that specifies a special state of the selected element(s). For example, :hover can be used to change a button's color when the user's pointer hovers over it.
:valid
represents any <input> or other <form> element whose contents validate successfully
input:valid {
border-color: green;
}
needs "required"
:invalid
any <input> or other <form> element whose contents fail to validate.
input:invalid {
border-color: red;
}
needs "required"
What Jonas sees
:disabled
represents any disabled element
:checked
selector represents any radio, checkbox, or option element that is checked or toggled to an on state
:focus
represents an element that has received focus
:placeholder-shown
represents any <input> or <textarea> element that is currently displaying placeholder text.
:not(
:not(
:not(
:not(
)
)
)
)
:disabled
doesn't represents any disabled element
:checked
selector represents any radio, checkbox, or option element that is not checked or toggled to an on state
:focus
represents an element that hasn't received focus
:placeholder-shown
represents any <input> or <textarea> element that is currently not displaying placeholder text.
:not(
:not(
:not(
:not(
)
)
)
)
input:invalid:not(:focus, :placeholder-shown) { ... }
input:invalid:not(:focus, :placeholder-shown) ~ .error-message { ... }
.form-group:has(input:invalid) { ... }
.form-group:has(input:not(:focus, :placeholder-shown):invalid) .error-message { ... }
.form-group:has(input:not(:focus, :placeholder-shown):invalid) label { ... }
.form-group:has(input:invalid) { ... }
.form-group:has(input:not(:focus, :placeholder-shown):invalid) .error-message { ... }
label:has( + input:not(:focus, :placeholder-shown):invalid) { ... }
label {
color: var(--color);
}
.form-field:has(:invalid) {
--color: red;
}
.form-field:has(:valid) {
--color: green;
}
form:focus-within {
border-color: blue;
}
.form-control:focus-within .hint {
color: red;
}
:focus-visible {
outline: 2px solid #000;
outline-offset: -2px;
box-shadow: 0 0 0 2px #fff, inset 0 0 0 3px #fff;
}
input {
appearance: none; /* Safari fix */
}
:root {
accent-color: deeppink;
}
form {
accent-color: deeppink;
}
input {
appearance: none;
...
}
/* Checked state */
input:checked::before {
...
}
Remove browser styles
Style custom checkmark with pseudo-elements
Preparing an SVG in Figma / Illustrator / XD
Resources
Default:
:focus
Buttons
Custom checkboxes and radio buttons
:invalid
:disabled
reset
form,
fieldset,
legend,
input,
button,
textarea,
select {
margin: 0;
padding: 0;
}
input,
button,
textarea,
select {
font-family: inherit;
font-size: max(16px, 1em);
}
button {
appearance: none;
border: 1px solid;
background: transparent;
cursor: pointer;
}
input[type="text"],
input[type="email"],
textarea {
appearance: none;
border: 1px solid;
background: transparent;
}
reset
Origin
0,0,0
0,0,1
@layer reset {
/* ... other reset rules */
input[type="text"] {
border: 1px solid gray;
}
}
@layer components {
/* ... other component rules */
.my-input {
border: 4px solid blue;
}
}
@layer reset, components, utilities;
@layer reset {
/* ... other reset rules */
input[type="text"] {
border: 1px solid gray;
}
}
@layer components {
/* ... other component rules */
.my-input {
border: 4px solid blue;
}
}
1
2
3
@layer reset, components, utilities;
@layer components {
/* ... other component rules */
.my-input {
border: 4px solid blue;
}
}
@layer reset {
/* ... other reset rules */
input[type="text"] {
border: 1px solid gray;
}
}
1
2
3
@layer reset, components, states;
@layer components {
/* Buttons, inputs etc. */
}
@layer states {
/* Make sure stats override, no matter specificity count */
:disabled {
background-color: #ddd;
color: #999;
}
:focus-visible {
outline: 2px solid var(--focus-color, currentColor);
outline-offset: 2px;
}
}
Default styling
:root {
--theme-color: 258 29% 43%;
--accent-color: 180 50% 43%;
}
input {
font-family: inherit;
font-size: max(16px, 1em);
padding: 0.25em 0.5em;
background-color: #fff;
border: 2px solid hsl(var(--theme-color));
}
input:is(:focus-visible, :hover) {
border-color: hsl(var(--accent-color));
}
Default styling
input:is([type="checkbox"], [type="radio"]) {
appearance: none;
/* custom styling */
}
Or with accent-color
form {
accent-color: var(--theme-color, hotpink);
/* checkbox, radio, progress, range etc. */
}
Form layout
form {
display: grid;
gap: 1.5rem;
}
.form-group {
display: grid;
gap: .3125rem;
}
form {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
form > input {
flex: 1 1 10ch;
}
input[type="email"] {
flex: 3 1 30ch;
}
.container {
container-type: inline-size;
}
@container (width > 25rem) {
.newsletter { ... }
}
axe Accessibility Linter
Error Lens
Differentiate between primary and secondary buttons
Make your form look & feel nice
Too many websites are too hard to read for too many people
@media (prefers-color-scheme: dark) {
/* Dark styles */
}
html {
--background-color: #222;
--foreground-color: #fafafa;
}
@media (prefers-color-scheme: dark) {
html {
--background-color: #fafafa;
--foreground-color: #222;
}
}
body {
background-color: var(--background-color);
color: var(--foreground-color);
}
@media (prefers-color-scheme: dark) {
/* Dark styles */
}