9

I have a table that will contain many columns and I would like to add input fields inside header cells, but I would like for the input to fit the width depending on the body content.

This is how it looks like without the input fields: enter image description here

And this is how it looks like with the input fields:

As it can be seen, columns like 'index' and 'Is Active' are taking too much space, and I would like to maintain the first layout as much as possible. I tried to set input width to 100% and auto, but it doesn't seem to help very much.

The current css looks like:

.table {
  font-family: Arial, Helvetica, sans-serif;
}

.table thead {
  position: sticky;
  top: 0;
}

.table thead th {
  border: 1px solid #e4eff8;
  background: white;
  cursor: pointer;
}

.table thead th.header-label {
  cursor: pointer;
  background: linear-gradient(0deg, #e4eff8, #4578a2 5%, #e4eff8 150%);
  color: white;
  border: 1px solid white;
}

.table th,
.table td {
  padding: 0.2rem 0.5rem;
  text-align: center;
}

.table td {
  border: 1px solid #e4eff8;
}

.table input {
  width: 100%;
}
<table class="table">
  <thead>
    <tr>
      <th class="header-label">Index</th>
      <th class="header-label">Name</th>
      <th class="header-label">Phone</th>
      <th class="header-label">Company</th>
      <th class="header-label">Registered</th>
      <th class="header-label">Is Active</th>
    </tr>
    <tr>
      <th><input type="number"></th>
      <th><input type="string"></th>
      <th><input type="string"></th>
      <th><input type="string"></th>
      <th><input type="date"></th>
      <th><input type="boolean"></th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>Paige Bean</td>
      <td>+1 (871) 458-2959</td>
      <td>MOREGANIC</td>
      <td>2018-12-27T11:28:50 -01:00</td>
      <td>false</td>
    </tr>
    <tr>
      <td>1</td>
      <td>Knox Holman</td>
      <td>+1 (880) 497-2808</td>
      <td>MAINELAND</td>
      <td>2017-05-07T02:54:22 -01:00</td>
      <td>false</td>
    </tr>
    <tr>
      <td>2</td>
      <td>Brandy Colon</td>
      <td>+1 (969) 513-2827</td>
      <td>NEXGENE</td>
      <td>2017-06-07T06:42:31 -00:00</td>
      <td>true</td>
    </tr>
    <tr>
      <td>3</td>
      <td>Suzette Austin</td>
      <td>+1 (863) 445-3604</td>
      <td>JETSILK</td>
      <td>2015-10-24T11:10:41 -01:00</td>
      <td>true</td>
    </tr>
    <tr>
      <td>4</td>
      <td>Downs Cain</td>
      <td>+1 (822) 574-2617</td>
      <td>INSECTUS</td>
      <td>2017-10-19T08:18:09 -01:00</td>
      <td>true</td>
    </tr>
    <tr>
      <td>5</td>
      <td>Michael Yang</td>
      <td>+1 (875) 492-3905</td>
      <td>DELPHIDE</td>
      <td>2016-08-15T01:31:55 -01:00</td>
      <td>false</td>
    </tr>
  </tbody>
</table>

So how do you make this happen with pure css, without hard coding the width of each column?

enter image description here

6
  • Please provide a short HTML snippet Commented Jun 23, 2020 at 10:39
  • i think a width auto with proper parent styling will work, but a snippet to play with the code would be great. Commented Jun 23, 2020 at 10:40
  • 1
    I made you a snippet Please update with relevant HTML Commented Jun 23, 2020 at 10:41
  • 1
    i am not sure if it is possible with css only, but you could do it with js Commented Jun 23, 2020 at 10:52
  • 1
    @Ayoub.A Yes, I've seen it. Thanks for adding, you spared me some time of creating it myself :) Commented Jun 23, 2020 at 11:15

5 Answers 5

6

Since the text on the input can't be predicted, every input with width:100% tries to get the most width it can. The solution is use a wrapping div with absolute positioning.

This is how it works (it obvious to me that OP understands the "wrapper div with absolute position" trick. The following is intended for someone learning CSS):

  • .table .tr-inputs th has position: relative so it serves as reference for child absolute positioned objects. We do not set anything about width (so it's completely auto), and we set a padding-bottom: 1.2rem to keep the th with the correct height for our absolute positioned elements (since absolute positioned elements are removed from the flow and "does not take any space").
  • .table .tr-inputs div is our wrapper div. We set position: absolute and set all top,right,left,bottom to 0. Then, it stretches it self to fill its relative positioned parent, which is our .table .tr-inputs th.
  • input has width: 100% so it takes all the width of its parent, which is our absolute positioned wrapper div.

.table {
  font-family: Arial, Helvetica, sans-serif;
}

.table thead {
  position: sticky;
  top: 0;
}

.table thead th {
  border: 1px solid #e4eff8;
  background: white;
  cursor: pointer;
}

.table thead th.header-label {
  cursor: pointer;
  background: linear-gradient(0deg, #e4eff8, #4578a2 5%, #e4eff8 150%);
  color: white;
  border: 1px solid white;
}

.table th,
.table td {
  padding: 0.2rem 0.5rem;
  text-align: center;
}

.table td {
  border: 1px solid #e4eff8;
}

.table .tr-inputs th {
  position: relative;
  padding: 0;
  padding-bottom: 1.2rem;
  margin: 0;
}

.table .tr-inputs div {
  position: absolute;
  display: inline-block;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

.table input {
  width: 100%;
  box-sizing: border-box;
}
<table class="table">
  <thead>
    <tr>
      <th class="header-label">Index</th>
      <th class="header-label">Name</th>
      <th class="header-label">Phone</th>
      <th class="header-label">Company</th>
      <th class="header-label">Registered</th>
      <th class="header-label">Is Active</th>
    </tr>
    <tr class="tr-inputs">
      <th>
        <div><input type="number"></div>
      </th>
      <th>
        <div><input type="string"></div>
      </th>
      <th>
        <div><input type="string"></div>
      </th>
      <th>
        <div><input type="string"></div>
      </th>
      <th>
        <div><input type="date"></div>
      </th>
      <th>
        <div><input type="boolean"></div>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>Paige Bean</td>
      <td>+1 (871) 458-2959</td>
      <td>MOREGANIC</td>
      <td>2018-12-27T11:28:50 -01:00</td>
      <td>false</td>
    </tr>
    <tr>
      <td>1</td>
      <td>Knox Holman</td>
      <td>+1 (880) 497-2808</td>
      <td>MAINELAND</td>
      <td>2017-05-07T02:54:22 -01:00</td>
      <td>false</td>
    </tr>
    <tr>
      <td>2</td>
      <td>Brandy Colon</td>
      <td>+1 (969) 513-2827</td>
      <td>NEXGENE</td>
      <td>2017-06-07T06:42:31 -00:00</td>
      <td>true</td>
    </tr>
    <tr>
      <td>3</td>
      <td>Suzette Austin</td>
      <td>+1 (863) 445-3604</td>
      <td>JETSILK</td>
      <td>2015-10-24T11:10:41 -01:00</td>
      <td>true</td>
    </tr>
    <tr>
      <td>4</td>
      <td>Downs Cain</td>
      <td>+1 (822) 574-2617</td>
      <td>INSECTUS</td>
      <td>2017-10-19T08:18:09 -01:00</td>
      <td>true</td>
    </tr>
    <tr>
      <td>5</td>
      <td>Michael Yang</td>
      <td>+1 (875) 492-3905</td>
      <td>DELPHIDE</td>
      <td>2016-08-15T01:31:55 -01:00</td>
      <td>false</td>
    </tr>
  </tbody>
</table>

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. I think we should use display: block; instead of inline-block for .table .tr-inputs div
@Gilboot Sometimes the backend platform can insert/passthrough undesirable characters, like newline, which could lead to gaps on the layout. With inline-block, even if these characters are present, there won't be gaps.
3
  • Never position: sticky <thead> elements. Use This solution instead: Table fixed header and scrollable body
  • Use background-color on <th> elements
  • Don't use padding on <th> elements - Use it on an inner .header-label <div>
  • .header-label should be an inner DIV if you want, no need to "classify" <th> elements
  • type="boolean" is an invalid type value. Use string or rather a type="checkbox"

/*QuickReset*/*{margin:0;box-sizing:border-box;}

/*
tableFixHead  
https://stackoverflow.com/a/47923622/383904
*/

.tableFixHead {
  overflow-y: auto;
  height: 180px;
}

.tableFixHead thead th {
  position: sticky;
  top: 0;
}

.table {
  border-collapse: collapse;
  font-family: Arial, Helvetica, sans-serif;
}

.table th {
  background: #fff;
}

.table th .header-label {
  padding: 0.2rem 0.5rem;
  cursor: pointer;
  background: linear-gradient(0deg, #e4eff8, #4578a2 5%, #e4eff8 150%);
  color: white;
  border: 1px solid white;
  white-space: nowrap;
}

.table td {
  padding: 0.2rem 0.5rem;
  text-align: center;
  border: 1px solid #e4eff8;
}

.table input {
  display: block;
  width: 100%;
  font: 14px/1.4 sans-serif;
}
<div class="tableFixHead">
  <table class="table">
    <thead>
      <tr>
        <th><div class="header-label">Index</div><input type="number"></th>
        <th><div class="header-label">Name</div><input type="string"></th>
        <th><div class="header-label">Phone</div><input type="string"></th>
        <th><div class="header-label">Company</div><input type="string"></th>
        <th><div class="header-label">Registered</div><input type="date"></th>
        <th><div class="header-label">Is Active</div><input type="string"></th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>0</td>
        <td>Paige Bean</td>
        <td>+1 (871) 458-2959</td>
        <td>MOREGANIC</td>
        <td>2018-12-27T11:28:50 -01:00</td>
        <td>false</td>
      </tr>
      <tr>
        <td>1</td>
        <td>Knox Holman</td>
        <td>+1 (880) 497-2808</td>
        <td>MAINELAND</td>
        <td>2017-05-07T02:54:22 -01:00</td>
        <td>false</td>
      </tr>
      <tr>
        <td>2</td>
        <td>Brandy Colon</td>
        <td>+1 (969) 513-2827</td>
        <td>NEXGENE</td>
        <td>2017-06-07T06:42:31 -00:00</td>
        <td>true</td>
      </tr>
      <tr>
        <td>3</td>
        <td>Suzette Austin</td>
        <td>+1 (863) 445-3604</td>
        <td>JETSILK</td>
        <td>2015-10-24T11:10:41 -01:00</td>
        <td>true</td>
      </tr>
      <tr>
        <td>4</td>
        <td>Downs Cain</td>
        <td>+1 (822) 574-2617</td>
        <td>INSECTUS</td>
        <td>2017-10-19T08:18:09 -01:00</td>
        <td>true</td>
      </tr>
      <tr>
        <td>5</td>
        <td>Michael Yang</td>
        <td>+1 (875) 492-3905</td>
        <td>DELPHIDE</td>
        <td>2016-08-15T01:31:55 -01:00</td>
        <td>false</td>
      </tr>
    </tbody>
  </table>
</div>

Comments

0

try this code

.table th {
    padding : 0;
    padding-right :  0.2rem;
}

.table td {
  padding: 0.2rem 0.5rem;
  text-align: center;
}

Instead of :

.table th,
.table td {
  padding: 0.2rem 0.5rem;
  text-align: center;
} 

Comments

0

As a workaround you could use absolute position inputs and relative position wrapper around it to match the column size.

I dont think it is a good solution but it works.

As mentioned in the answer from @Roko C. Buljan there are some points you could do better.

.table {
  font-family: Arial, Helvetica, sans-serif;
}

.table thead {
  position: sticky;
  top: 0;
}

.table thead th {
  border: 1px solid #e4eff8;
  background: white;
  cursor: pointer;
}

.table thead th.header-label {
  cursor: pointer;
  background: linear-gradient(0deg, #e4eff8, #4578a2 5%, #e4eff8 150%);
  color: white;
  border: 1px solid white;
}

.table th,
.table td {
  padding: 0.2rem 0.5rem;
  text-align: center;
  position: realtive;
}

.table td {
  border: 1px solid #e4eff8;
}

.table .input_wrapper{
  position: relative;
  width: 100%;
  display: block;
}

.table .input_wrapper::after{
  content: "+";
  color: rgba(0, 0, 0, 0);
  display: block;
}

.table input {
  position: absolute;
  width: 100%;
  left: 0;
}
<table class="table">
  <thead>
    <tr>
      <th class="header-label">Index</th>
      <th class="header-label">Name</th>
      <th class="header-label">Phone</th>
      <th class="header-label">Company</th>
      <th class="header-label">Registered</th>
      <th class="header-label">Is Active</th>
    </tr>
    <tr>
      <th>
        <div class="input_wrapper"><input type="number"></div>
      </th>
      <th>
        <div class="input_wrapper"><input type=" string"></div>
      </th>
      <th>
        <div class="input_wrapper"><input type="string"></div>
      </th>
      <th>
        <div class="input_wrapper"><input type="string"></div>
      </th>
      <th>
        <div class="input_wrapper"><input type="date"></div>
      </th>
      <th>
        <div class="input_wrapper"><input type="boolean"></div>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>0</td>
      <td>Paige Bean</td>
      <td>+1 (871) 458-2959</td>
      <td>MOREGANIC</td>
      <td>2018-12-27T11:28:50 -01:00</td>
      <td>false</td>
    </tr>
    <tr>
      <td>1</td>
      <td>Knox Holman</td>
      <td>+1 (880) 497-2808</td>
      <td>MAINELAND</td>
      <td>2017-05-07T02:54:22 -01:00</td>
      <td>false</td>
    </tr>
    <tr>
      <td>2</td>
      <td>Brandy Colon</td>
      <td>+1 (969) 513-2827</td>
      <td>NEXGENE</td>
      <td>2017-06-07T06:42:31 -00:00</td>
      <td>true</td>
    </tr>
    <tr>
      <td>3</td>
      <td>Suzette Austin</td>
      <td>+1 (863) 445-3604</td>
      <td>JETSILK</td>
      <td>2015-10-24T11:10:41 -01:00</td>
      <td>true</td>
    </tr>
    <tr>
      <td>4</td>
      <td>Downs Cain</td>
      <td>+1 (822) 574-2617</td>
      <td>INSECTUS</td>
      <td>2017-10-19T08:18:09 -01:00</td>
      <td>true</td>
    </tr>
    <tr>
      <td>5</td>
      <td>Michael Yang</td>
      <td>+1 (875) 492-3905</td>
      <td>DELPHIDE</td>
      <td>2016-08-15T01:31:55 -01:00</td>
      <td>false</td>
    </tr>
  </tbody>
</table>

Comments

0

this is a simple javascript solution if you want:

change this section of HTML:

<tr>
  <th><div class="input-container"><input type="number"></div></th>
  <th><div class="input-container"><input type="string"></div></th>
  <th><div class="input-container"><input type="string"></div></th>
  <th><div class="input-container"><input type="string"></div></th>
  <th><div class="input-container"><input type="date"></div></th>
  <th><div class="input-container"><input type="boolean"></div></th>
</tr>

add this to your CSS:

table .input-container {
  width: 0;
}

and link this javascript to your HTML:

let cont = document.querySelectorAll('.input-container')
for (let i = 0; i < cont.length; i++) {
  cont[i].style.width = cont[i].parentNode.offsetWidth + 'px'
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.