Search code examples
cssformsgridfieldset

I have a problem with CSS GRID on FORMs which have FIELDSETs in them - GRID ends up on both parent and child and then breaks


Basically I am using CSS grid to make forms multi-column layout and this works fine for normal forms, but if the forms have FIELDSETS then it doesn't work as they are a parent of the form elements so in case of FIELDSETS I need the GRID to be on the FIELDSET instead of the FORM element.

But below CSS adds it to both FORM and FIELDSET (ie two nested GRIDS) and then breaks the GRID structure - only want one.

I'm not sure how to say "put the GRID on the form element if it's got NO FIELDSET child, otherwise put it on the FIELDSET instead"

ie

 <form class="form-horizontal">
   <fieldset GRID>
     <div class="form-group">
     </div>
     <div class="form-group">
     </div>
   </fieldset>
 </form>

or

 <form class="form-horizontal" GRID>
     <div class="form-group">
     </div>
     <div class="form-group">
     </div>
 </form> 
.form-horizontal, .form-horizontal FIELDSET {
    display: grid;
    /* grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); */
    grid-gap: 0px;
    grid-template-columns: repeat(auto-fill, minmax(min(350px, 100%), 1fr));
}

Above CSS ends up adding to both like

 <form class="form-horizontal" GRID>
   <fieldset GRID>
     <div class="form-group">
     </div>
     <div class="form-group">
     </div>
   </fieldset>
 </form>

Tried using CSS :not operator but not really sure how to do it in this case. Also looked at the display: contents feature but not sure how to use that here... i don't want the FIELDSET to lose all block styling and doesn't seem to work. But I do want the GRID on only the FORM element in both cases and skip over the FIELDSET element like display: contents is supposed to do.


Solution

  • below an example that belongs to my earlier comment:

    You need to make the fieldset fill the whole row as well after it inherits display and grid-template-columns . add for the fieldset : grid-column:1/-1; and it should lay through every columns of the form. (fieldset should be written with lowercase btw )

    fieldset has a padding that offset its div from the div which are direct children.

    .form-horizontal {
      display: grid;
      grid-gap: 0px;
      grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr));
    }
    
    .form-horizontal fieldset {
      display: inherit;
      grid-gap: inherit;
      grid-template-columns: inherit;
      grid-column: 1/-1;
    }
    
    form div {
      border: solid;
    }
    <form class="form-horizontal">
      <fieldset>
        <div class="form-group">
          div in fieldset
        </div>
        <div class="form-group">
          div in fieldset
        </div>
      </fieldset>
    
      <fieldset>
        <div class="form-group">
          div in fieldset
        </div>
        <div class="form-group">
          div in fieldset
        </div>
      </fieldset>
    </form>
    
    or
    
    <form class="form-horizontal">
      <div class="form-group">
        div direct child
      </div>
      <div class="form-group">
        div direct child
      </div>
    
      <fieldset>
        <div class="form-group">
          div in fieldset
        </div>
        <div class="form-group">
          div in fieldset
        </div>
      </fieldset>
    </form>
    
    custom attributes are to be written via the data-attribute syntax, so GRID would better be data-grid ;)

    demo playing with spacing

    * {
      box-sizing: border-box;
    }
    
    .form-horizontal {
      padding: 0.9em;
      display: grid;
      grid-gap: 0px;
      grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr));
    }
    
    .form-horizontal fieldset {
      display: inherit;
      grid-gap: inherit;
      grid-template-columns: inherit;
      grid-column: 1/-1;
      margin: 0 -.9em;
    }
    
    form div {
      border: solid;
    }
    <form class="form-horizontal">
      <fieldset>
        <div class="form-group">
          div in fieldset
        </div>
        <div class="form-group">
          div in fieldset
        </div>
      </fieldset>
    
      <fieldset>
        <div class="form-group">
          div in fieldset
        </div>
        <div class="form-group">
          div in fieldset
        </div>
      </fieldset>
    </form>
    
    or
    
    <form class="form-horizontal">
      <div class="form-group">
        div direct child
      </div>
      <div class="form-group">
        div direct child
      </div>
    
      <fieldset>
        <div class="form-group">
          div in fieldset
        </div>
        <div class="form-group">
          div in fieldset
        </div>
      </fieldset>
    </form>