I have an html form that includes a wide table along with the expected label/input fields. The requirement is that the window/frame has the ability to scroll horizontally, scrolling the table as expected, but leaving the fields in place during that scroll.
Trying to place the table in a div that can scroll horizontally is not good enough, as this results in the need to scroll down to the bottom of the table to find the scrollbar – hence the h scrollbar needs to sit on the whole frame.
I have tried the following code – and it’s close, but when (1) I’d prefer to have the red div’s to be 100vw instead of 50vw and (2) it only seems to work when the screen is wider … thinner screens seem to keep the inputs sticky for a while – and then they scroll off
.form-container > div {
position:sticky;
left:10px;
color:red;
border:solid 1px red;
width:50vw;
}
Demo – also on JSFiddle
function createRowCopies(tr, num) {
if (!tr || num <= 0) return;
// Ensure the `tr` element is valid
if (!(tr instanceof HTMLTableRowElement)) {
console.error("Invalid row element passed to createRowCopies.");
return;
}
// Loop to create and append copies
for (let i = 0; i < num; i++) {
// Clone the row
const clone = tr.cloneNode(true);
// Append the cloned row right after the original
tr.parentNode.insertBefore(clone, tr.nextSibling);
// Update `tr` reference to the last inserted row
tr = clone;
tr.children[0].innerHTML = i + 2;
}
}
createRowCopies(document.querySelector('tbody tr'), 30);
.form-container {
padding: 10px;
border: 1px solid #ccc;
display: unset;
max-width: 100%;
/* Ensures it doesn't exceed the viewport width */
}
.form-container>div {
position: sticky;
left: 10px;
color: red;
border: solid 1px red;
width: 50vw;
}
label {
display: block;
padding: 10px;
}
table {
border-collapse: collapse;
}
th,
td {
border: 1px solid #ccc;
padding: 8px;
white-space: nowrap;
}
thead th {
background-color: #f8f8f8;
position: sticky;
}
<div class="form-container">
<div>
<label>
Name:
<input type="text" name="name" />
</label>
</div>
<div>
<label>
Email:
<input type="email" name="email" />
</label>
</div>
<table>
<thead>
<tr>
<th>#</th>
<th>Column 1</th>
<th style="min-width: 200px">Column 2</th>
<th style="min-width: 100px">Column 3</th>
<th>Column 4</th>
<th>Column 5</th>
<th>Column 6</th>
<th>Column 7</th>
<th>Column 8</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Data 1</td>
<td>Data 2</td>
<td>Data 3</td>
<td>Data 4</td>
<td>Data 5</td>
<td>Data 6</td>
<td>Data 7</td>
<td>Data 8</td>
</tr>
</tbody>
</table>
<div>
<label>
Comments:
<textarea name="comments" rows="4"></textarea>
</label>
</div>
<div>
<button type="submit">Submit</button>
</div>
</div>
…. or if you want to play with the code (or change the screen width) then use https://jsfiddle.net/ntsf7ajp
2
Answers
A better way to solve your problem would be to make only the table scrollable not the entire body/document.
.form-container>div
), you can use the:not
selector in combination with direct descendant selector like this:Full Code Snippet:
JSFiddle here.
sticky
elements stop being sticky during the scrolling due to the fact that they reach the end of.form-container
width, which happens to be much narrower than its content size. This occurs for several reasons:By default, a
<div>
has the CSS propertyoverflow
set tovisible
. This means that any content larger than the<div>
will overflow and be displayed outside of it without expanding the container to fit the content.A
<table>
inherently displays all its content without shrinking. If the table’s content is too wide for the container, it will overflow rather than adjust its width or force the container to grow.You’ve specified a
max-width
of100%
, which restricts the<div>
container to 100% of its parent’s width, regardless of whether its content exceeds that width.The use of
display: unset
in the context of JSFiddle resets thedisplay
property to its default value (inline
in this case). This behavior is incompatible with explicitly forcing a width, as shown below.To achieve the desired behavior, you can set
display: block
on the<div>
and usewidth: max-content
or similar properties to ensure the container adjusts to its content’s width.