Search code examples
cssradio-buttonlabelcss-gridfieldset

CSS grid: <label> and <input type="radio"> render on a different row?


I started studying the CSS grid and I'm trying to build a form. I can't wrap my head around why the <label> and <input type="radio"> are being rendered on a different row. I want them both in the same area. And I don't want to work with implicit labeling. (As I want to render the radio button left of its label.) Is it possible to render them both in one area (or 'cell' if you like)? If not, the only solution is to create a separate grid with three columns?

A second question: I've read already that the <fieldset> doesn't work well with grid. To solve this, I've put a <div> in it. But for some reason, the <fieldset> can't be part of the <section>. (While these radio buttons do, semantic wise, belong to this section. What seems to be the problem?

Thanks in advance!

form {
padding: 1em;
}

section {
  display: contents;
}

fieldset {
  padding: 0;
  margin: 0;
  border: none;
}

.twoColumns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-areas: 
    "leftColumn rightColumn";
  gap: 1em;
  padding-bottom: 1em;
  justify-items: start;
}

.twoColumns > label {
  grid-column: leftColumn;
}

.twoColumns > input {
  grid-column: rightColumn;
}

.twoColumns-right > label, 
.twoColumns-right > input {
  grid-column: rightColumn;
}
<link href="https://necolas.github.io/normalize.css/latest/normalize.css" rel="stylesheet" type="text/css">

<form id="myForm">
  <section class="twoColumns" title="Title1">
    <h1>Title h1</h1>
    <label for="name">Name:</label>
    <input type="text" id="name" name="name">
    <label for="surname">surname:</label>
    <input type="text" id="surname" name="surname">
  </section>
  <fieldset>
    <div class="twoColumns twoColumns-right">
      <legend>Gender:</legend>
      <input type="radio" id="man" name="gender" value="man">
      <label for="man">Man</label>
      <input type="radio" id="woman" name="gender" value="woman">
      <label for="vrouw">Woman</label>
    </div>
  </fieldset>
</form>

I tried a new three-column grid. This works, but creates a new problem: the two-grid and three-grid aren't lining up layout wise.

Tried applying display: inline-block on both label and input, this doesn't work.

Played around with display: contents. No (positive) result.


Solution

  • The Grids layout works by positioning each child element in individual grid cells. It is also worth noting that bare text will be treated as an individual grid cell as well.

    Therefore, as you have label and input as direct child elements of the grid container, they are in separate grid cells. In order to treat the label and input as one unit to be positioned in the same cell, you'll need to wrap them inside of another element, such as div.

    Also, realize that the legend element is permitted only to be the first child of a fieldset. Therefore, it is invalid for you to put legend as the first child of a div.

    form {
      display: grid;
      grid-template-columns: max-content auto;
      justify-items: start;
      gap: 1em;
      padding: 1em;
    }
    
    label {
      grid-column-start: 1;
    }
    
    input {
      grid-column-start: 2;
    }
    <h1>Title h1</h1>
    <form>
      <label for="name">Name:</label>
      <input type="text" id="name" name="name">
      <label for="surname">surname:</label>
      <input type="text" id="surname" name="surname">
        Gender:
      <div class="gender">
        <input type="radio" id="man" name="gender" value="man">
        <label for="man">Man</label>
        <br>
        <input type="radio" id="woman" name="gender" value="woman">
        <label for="woman">Woman</label>
      </div>
    </form>