<main>
  <h1>This demo does not work in FireFox</h1>
  <form>
    <div class="control">
      <label for="name">Name</label>
      <div class="control__input">
        <input id="name" name="name" required />
        <svg class="icon icon-check"><use xlink:href="#icon-check"></use></svg>
        <svg class="icon icon-cancel"><use xlink:href="#icon-cancel"></use></svg>
      </div>
    </div>
    <div class="control">
      <label for="email">Email</label>
      <div class="control__input">
        <svg class="icon icon-email"><use xlink:href="#icon-email"></use></svg>
        <input id="email" type="email" name="email" required />
        <svg class="icon icon-check"><use xlink:href="#icon-check"></use></svg>
        <svg class="icon icon-cancel"><use xlink:href="#icon-cancel"></use></svg>
      </div>
    </div>

    <br />

    <fieldset>
      <legend>What's your fave frontend language</legend>
      <div class="cards">
        <div class="card card--html">
          <label for="html">HTML</label>
          <input
                 id="html"
                 type="radio"
                 name="fe-fave"
                 aria-describedby="html-description"
                 class="visually-hidden"
                 />
          <p id="html-description">The bones of any good website</p>
        </div>
        <div class="card card--css">
          <label for="css">CSS</label>
          <input
                 id="css"
                 type="radio"
                 name="fe-fave"
                 aria-describedby="css-description"
                 class="visually-hidden"
                 />
          <p id="css-description">Styles to make your mamma proud</p>
        </div>
        <div class="card card--js">
          <label for="js">JavaScript</label>
          <input
                 id="js"
                 type="radio"
                 name="fe-fave"
                 aria-describedby="js-description"
                 class="visually-hidden"
                 />
          <p id="js-description">Fancy-pantsy movements and stuff</p>
        </div>
      </div>
    </fieldset>

    <br />

    <fieldset>
      <legend>Favorite Starter Pokemon</legend>

      <div class="flex justify-between">
        <div class="control">
          <input
                 id="bulbasaur"
                 type="radio"
                 name="selection"
                 value="bulbasaur"
                 />
          <label for="bulbasaur">Bulbasaur</label>
        </div>

        <div class="control">
          <input
                 id="charmander"
                 type="radio"
                 name="selection"
                 value="charmander"
                 />
          <label for="charmander">Charmader</label>
        </div>

        <div class="control">
          <input
                 id="squirtle"
                 type="radio"
                 name="selection"
                 value="squirtle"
                 />
          <label for="squirtle">Squirtle</label>
        </div>
      </div>

      <div class="pokemon pokemon--bulbasaur">
        <img
             src="https://assets.pokemon.com/assets/cms2/img/pokedex/full/001.png"
             width="300"
             height="300"
             alt="Bulbasaur"
             />
        <p>
          Bulbasaur can be seen napping in bright sunlight. There is a seed on
          its back. By soaking up the sun's rays, the seed grows progressively
          larger.
        </p>
        <ul>
          <li>Height: 2' 04"</li>
          <li>Weight: 15.2 lbs</li>
          <li>Type: Grass/Poison</li>
          <li>Weaknesses: Fire, Psychic, Flying, Ice</li>
        </ul>
      </div>

      <div class="pokemon pokemon--charmander">
        <img
             src="https://assets.pokemon.com/assets/cms2/img/pokedex/full/004.png"
             width="300"
             height="300"
             alt="Charmander"
             />
        <p>
          The flame that burns at the tip of its tail is an indication of its
          emotions. The flame wavers when Charmander is enjoying itself. If
          the Pokémon becomes enraged, the flame burns fiercely.
        </p>
        <ul>
          <li>Height:1' 08"</li>
          <li>Weight: 19.8 lbs</li>
          <li>Type: Water</li>
          <li>Weaknesses: Grass, Electric</li>
        </ul>
      </div>

      <div class="pokemon pokemon--squirtle">
        <img src="https://assets.pokemon.com/assets/cms2/img/pokedex/full/007.png" width="300" height="300" alt="Squirtle" />
        <p>
          Squirtle's shell is not merely used for protection. The shell's
          rounded shape and the grooves on its surface help minimize
          resistance in water, enabling this Pokémon to swim at high speeds.
        </p>
        <ul>
          <li>Height: 2' 00"</li>
          <li>Weight: 18.7 lbs</li>
          <li>Type: Fire</li>
          <li>Weaknesses: Water, Ground, Rock</li>
        </ul>
      </div>
    </fieldset>

    <!-- Challenge: Do the same with checkboxes -->

    <br />

    <div class="control">
      <input
             id="checkme"
             type="checkbox"
             name="learned"
             class="switch"
             required
             />
      <label for="checkme">I learned something cool!</label>
    </div>

    <br />

    <button type="submit">Submit</button>
  </form>
</main>


<svg aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <symbol viewBox="0 0 24 24" id="icon-cancel"><path fill="currentColor" d="m8.4 17l3.6-3.6l3.6 3.6l1.4-1.4l-3.6-3.6L17 8.4L15.6 7L12 10.6L8.4 7L7 8.4l3.6 3.6L7 15.6Zm3.6 5q-2.075 0-3.9-.788q-1.825-.787-3.175-2.137q-1.35-1.35-2.137-3.175Q2 14.075 2 12t.788-3.9q.787-1.825 2.137-3.175q1.35-1.35 3.175-2.138Q9.925 2 12 2t3.9.787q1.825.788 3.175 2.138q1.35 1.35 2.137 3.175Q22 9.925 22 12t-.788 3.9q-.787 1.825-2.137 3.175q-1.35 1.35-3.175 2.137Q14.075 22 12 22Zm0-2q3.35 0 5.675-2.325Q20 15.35 20 12q0-3.35-2.325-5.675Q15.35 4 12 4Q8.65 4 6.325 6.325Q4 8.65 4 12q0 3.35 2.325 5.675Q8.65 20 12 20Zm0-8Z"></path></symbol>
    <symbol viewBox="0 0 24 24" id="icon-check"><path fill="currentColor" d="m10 16.4l-4-4L7.4 11l2.6 2.6L16.6 7L18 8.4Z"></path></symbol>
    <symbol viewBox="0 0 24 24" id="icon-email"><path fill="currentColor" d="M12 22q-2.05 0-3.875-.788q-1.825-.787-3.187-2.15q-1.363-1.362-2.15-3.187Q2 14.05 2 12q0-2.075.788-3.887q.787-1.813 2.15-3.175Q6.3 3.575 8.125 2.787Q9.95 2 12 2q2.075 0 3.887.787q1.813.788 3.175 2.151q1.363 1.362 2.15 3.175Q22 9.925 22 12v1.45q0 1.475-1.012 2.512Q19.975 17 18.5 17q-.9 0-1.675-.4t-1.275-1.05q-.675.675-1.587 1.063Q13.05 17 12 17q-2.075 0-3.537-1.463Q7 14.075 7 12t1.463-3.538Q9.925 7 12 7t3.538 1.462Q17 9.925 17 12v1.45q0 .725.45 1.137q.45.413 1.05.413q.6 0 1.05-.413q.45-.412.45-1.137V12q0-3.275-2.363-5.638Q15.275 4 12 4Q8.725 4 6.362 6.362Q4 8.725 4 12t2.362 5.637Q8.725 20 12 20h5v2Zm0-7q1.25 0 2.125-.875T15 12q0-1.25-.875-2.125T12 9q-1.25 0-2.125.875T9 12q0 1.25.875 2.125T12 15Z"></path></symbol>
  </defs>
</svg>
:root {
  --text: #333;
  --highlight: mediumpurple;
  --highlightDark: darkslateblue;
  --outline: plum;
  --error: tomato;
  --outlineError: pink;
  --success: limegreen;
  --outlineSuccess: palegreen;
}
body {
  font: 1.25rem/1.5 'Manrope';
  color: var(--text);
  background-color: lavender;
}
main {
  max-inline-size: 48rem;
  margin-inline: auto;
  border: 0.125rem solid;
  padding: 0.75rem;
  background: #fff;
}
input,
select,
button {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
}
input[type="radio"],
input[type="checkbox"] {
  appearance: none;
  inline-size: 1em;
  block-size: 1em;
  margin: 0;
  border: .125rem solid;
  border-radius: .125em;
  vertical-align: middle;
  color: inherit;
  transition: box-shadow 0.2s ease;
}
input[type='radio'] {
  border-radius: 50%;
}
input[type="checkbox"]:checked,
input[type="radio"]:checked {
  box-shadow: inset 0 0 0 .25em var(--highlight);
}
fieldset {
  margin: 0;
  border: .125rem solid;
  border-radius: .25rem;
}
button {
  border-radius: .25rem;
  color: white;
  background-color: var(--highlightDark);
}
:focus-visible {
  outline: 3px solid var(--outline);
  outline-offset: 1px;
}
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* UTILS */
.visually-hidden {
  border: 0;
  clip: rect(0 0 0 0);
  height: auto;
  margin: 0;
  overflow: hidden;
  padding: 0;
  position: absolute !important;
  width: 1px;
  white-space: nowrap;
}
.icon {
  display: inline-block;
  inline-size: 1em;
  block-size: 1em;
  stroke-width: 0;
  stroke: currentColor;
  fill: currentColor;
}
.flex {
  display: flex;
}
.justify-between {
  justify-content: space-between;
}
.mbe-8 {
  margin-block-end: .5rem;
}

/* CUSTOM CONTROLS */
.control:has(:where(input[type="radio"], input[type="checkbox"])) {
  display: flex;
  align-items: center;
  gap: .25rem;
}
.control__input {
  display: flex;
  align-items: center;
  gap: .125rem;
  border: .125rem solid;
  border-radius: .25rem;
  padding: .25rem;
}
.control__input :where(input, select, textarea) {
  flex-grow: 1;
  border: 0;
  padding: 0;
  background-color: transparent;
  outline: 0;
}
.control__input:has(:focus-visible),
.control :where([type="radio"], [type="checkbox"]):focus-visible,
.card:has(:focus-visible) {
  outline: 3px solid var(--outline);
}
.control__input :where(.icon-check, .icon-cancel) {
  display: none;
}
.control:has(:focus:invalid) {
  color: var(--error);
}
.control:has(:focus:invalid) .control__input {
  outline-color: var(--outlineError);
}
/* Controls that do not include radio or checkbox, and that also have valid inputs currently focused */
.control:has(:where(:not([type="radio"], [type="checkbox"])):focus:valid) {
  color: var(--success);
}
.control:has(:where(:not([type="radio"], [type="checkbox"])):focus:valid) .control__input {
  outline-color: var(--outlineSuccess);
}
.control:has(:focus:invalid) .icon-cancel,
.control:has(:focus:valid) .icon-check {
  display: unset
}

/**
* SWITCH
*/
input[type="checkbox"].switch {
  appearance: none;
  display: inline-flex;
  align-items: center;
  width: 2.5em;
  height: 1.3em;
  border-radius: 10000px;
  padding: .125em;
  box-shadow: none;
}
input[type="checkbox"].switch:before {
  content: '';
  width: .9em;
  height: .9em;
  border: 1px solid;
  border-radius: 10000px;
  transition: transform 0.3s ease, background 0.3s ease;
}
input[type="checkbox"].switch:checked:before {
  background-color: var(--highlight);
  transform: translateX(1em);
}

/** CARDS */
.cards {
  display: grid;
  gap: .5rem;
  grid-template-columns: repeat(3, 1fr);
}
.card {
  position: relative;
  border: .125rem solid;
  border-radius: .5rem;
  padding: 1rem;
  background: #fff;
  transition: box-shadow 0.2s ease;
}
.card :first-child {
  margin-block-start: 0;
}
.card :last-child {
  margin-block-end: 0;
}
.card :where(svg, label) {
  display: block;
  margin: auto;
}
.card label {
  text-align: center;
}
.card label:after {
  content: '';
  position: absolute;
  inset: 0;
}
.card a {
  position: relative;
}
.card img {
  display: block;
  margin-left: auto;
  margin-right: auto;
}
.card:has(input:checked) {
  box-shadow: inset 0 0 0 .25em var(--highlight);
}

/**
* POKEMON
*/
.pokemon {
  display: none;
}
.pokemon img {
  display: block;
  margin: auto;
}
form:has(#bulbasaur:checked) .pokemon--bulbasaur,
form:has(#charmander:checked) .pokemon--charmander,
form:has(#squirtle:checked) .pokemon--squirtle {
  display: block;
}

/**
* VALIDATION
*/
form:has(:invalid) :where(button:not([type]), button[type="submit"]) {
  opacity: 0.7;
  color: var(--text);
  background: whitesmoke;
  cursor: not-allowed;
}
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.