<h2>Resizable Columns using <code>&lt;input type="range"&gt;</code> and CSS Custom Properties</h2>
<div>
  <table>
    <thead>
      <tr>
        <th>ID</th>
        <th>First Name</th>
        <th>Last Name</th>
        <th>City</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>1</td>
        <td>Apu</td>
        <td>Nahasapeemapetilon</td>
        <td>Springfield</td>
      </tr>
      <tr>
        <td>2</td>
        <td>Bruce</td>
        <td>Wayne</td>
        <td>Gotham City</td>
      </tr>
      <tr>
        <td>3</td>
        <td>Clark</td>
        <td>Kent</td>
        <td>Metropolis</td>
      </tr>
      <tr>
        <td>3</td>
        <td>Donald</td>
        <td>Duck</td>
        <td>Duckburg</td>
      </tr>
    </tbody>
  </table>
</div>
<p><a href="https://dev.to/madsstoumann/accessible-resizable-table-columns-5eof">Article and discussion at dev.to</a></p>
/* Chrome, Edge, Safari */
[data-table-col] {
  --rng-h: 1px;
  --rng-thumb-bgc: transparent;
  --rng-thumb-h: var(--th, 6rem);
  --rng-thumb-ico: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="M15.5 8l-4.5 4.5v-3.5h-6v3.5l-4.5-4.5 4.5-4.5v3.5h6v-3.5l4.5 4.5z"></path></svg>');
  --rng-thumb-w: 2rem;

  background: transparent;
  box-sizing: border-box;
  font-family: inherit;
  height: 1px;
  margin: 0;
  outline: none;
  position: absolute;
  top: 0;
  width: 100%;
}
[data-table-col]::-webkit-slider-thumb {
  background-color: var(--rng-thumb-bgc);
  background-position: 50% 0;
  background-repeat: no-repeat;
  background-size: 80%;
	border: 0;
  cursor: ew-resize;
  height: var(--rng-thumb-h);  
  width: var(--rng-thumb-w);
}
[data-table-col]:focus-visible::-webkit-slider-thumb {
  --rng-thumb-bgc: rgb(0, 0, 0, 0.1);
  background-image: var(--rng-thumb-ico);
  outline: 2px solid rgb(0, 0, 0, 0.8)
}
[data-table-col]::-webkit-slider-runnable-track {
  background: transparent;
  height: var(--rng-h);
}
[data-table-col],
[data-table-col]::-webkit-slider-runnable-track,
[data-table-col]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
}

/* Firefox */
@-moz-document url-prefix() {
  [data-table-col] {
    top: calc(var(--rng-thumb-h) / 2);
  }
}
[data-table-col]::-moz-range-thumb {
	background-color: var(--rng-thumb-bgc);
  background-position: 50% 0;
  background-repeat: no-repeat;
  background-size: 80%;
	border: 0;
  cursor: ew-resize;
  height: var(--rng-thumb-h);
	width: var(--rng-thumb-w);
}
[data-table-col]:focus-visible::-moz-range-thumb {
  --rng-thumb-bgc: rgb(0, 0, 0, 0.1);
  background-image: var(--rng-thumb-ico);
  outline: 2px solid rgb(0, 0, 0, 0.8);
}

[data-table-parent] {
  position: relative;
}

/* For this demo */
body {
  background-color: #cfe3e8;
  font-family: ui-sans-serif, system-ui, sans-serif;
  margin: 0 auto;
  max-width: 950px;
  padding: 1rem;
}
code {
  background: #e3fffd;
}
table {
  border-collapse: collapse;
  table-layout: fixed;
  width: 100%;
}
td, th {
  border: 1px solid silver;
  padding: 0.5em 1em;
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
}
td {
  background-color: #fff;
}
th {
  background-color: #96a5b2;
}
function resizeTable(table, selector = 'thead tr th',  minWidth = 5) {
  if (!table) return;
  const cols = table.querySelectorAll(selector);
  const parent = table.parentNode;
  const tableWidth = table.offsetWidth;
  let value = 0;

  parent.dataset.tableParent = '';
  parent.style.setProperty(`--th`, `${table.offsetHeight}px`);

  cols.forEach((col, index) => {
    const colWidth = parseInt(100 / (tableWidth / col.offsetWidth));
    col.style.width = `calc(1% * var(--c${index}))`;
    table.style.setProperty(`--c${index}`, colWidth);

    if (index > 0) {
      const input = document.createElement('input');
      input.dataset.tableCol = index;
      input.setAttribute('aria-hidden', true);
      input.type = 'range';
      input.value = value;
      parent.appendChild(input);

      input.addEventListener('input', () => {
        if (input.value < minWidth) input.value = minWidth;
        if (input.value > 100 - minWidth) input.value = 100 - minWidth;

        const next = input.nextElementSibling;
        const prev = input.previousElementSibling;

        if (next?.nodeName === 'INPUT' && (input.valueAsNumber > (next.valueAsNumber - minWidth))) {
          input.value = next.valueAsNumber - minWidth;
          return;
        }
        if (prev?.nodeName === 'INPUT' && (input.valueAsNumber < (prev.valueAsNumber + minWidth))) {
          input.value = prev.valueAsNumber + minWidth;
          return;
        }

        table.style.setProperty(`--c${index-1}`, prev?.nodeName === 'INPUT' ? input.valueAsNumber - prev.valueAsNumber : input.valueAsNumber);
        table.style.setProperty(`--c${index}`, next?.nodeName === 'INPUT' ? next.valueAsNumber - input.valueAsNumber : 100 - input.valueAsNumber);
      });
    }
    value += colWidth;
  });
  
/* HACK TO INIT FIREFOX: Trigger input event on last range to re-position sliders */
	const lastRange = table.parentNode.lastChild;
	if (lastRange?.nodeName === 'INPUT') {
		lastRange.dispatchEvent(new Event('input', {
			bubbles: true,
			cancelable: true,
		}));
	}
}
/* Init Demo */
const table = document.querySelector('table');
resizeTable(table);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.