"list-view" custom element:

This element displays objects in a list-style view. The list is selectable (single or multiple) and supports keyword navigation and selection. It is possible to rearrange items or add custom icons to the list. This element uses the standard "select" HTML element to be compatible with native HTML elements.


Title Path Location

If you dont need the drag and drop support, use simple-list-view element instead


To add a new row, first use option(parts, name, value, selected) method to create a new option object, then use the insert(at) method. "parts" is an array that includes information for each column. The "parts[].name" property controls the title of the column. The "name" is the content that is inserted into the HTML "option" element. This content is used for keyboard navigation (for instance, press "z" to select the "zero" element). The "value" is the value of the option element. To select an entry set the "selected" to true.

const option = e.option([
  {name: '', part: 'file'},
  {name: 'zero'},
  {name: '3'},
  {name: '4'}
], 'zero', 0, false);


You can optionally use the "part" property to customize the look of the column with CSS.

list-view::part(file) {
  background: url(file.svg) center center no-repeat;
  background-size: 16px;

The header elements can be complex HTML elements. For instance in this example, "Location" uses the HTML "b" element.

    <span width="0">Path</span>
    <span width="1fr"><b>Location</b></span>

You can later use JavaScript to remove a row from this view (similar to a SELECT element):


To remove all items use:


To get the list of selected options use (similar to a SELECT element):


To get the list of all options use (similar to a SELECT element):


Similar to the HTML "SELECT" element, this custom element dispatches the "change" event when selection changes. You can get the selected index, selected value, and the parts object using the following code.

e.addEventListener('change', e => {
  console.log('value', e.target.value);
  console.log('selectedIndex', e.target.selectedIndex);

Keyboard Navigation

You can select multiple items with your mouse (use Ctrl + Click on Windows and Command + Click on macOS). Use Ctrl + A or Command + A to select all items, and use ArrowUp and ArrowDown to navigate between items. The "list-view" and "simple-list-view" also support tab navigation between list views. Use the Tab key to select the next view and Shift + Tab key to switch to the previous one.

Hide and Show a Column

To hide a column, set the "width" attribute of the column to zero. You can display the column back by adjusting its width later.

Drag and Drop Support

By default, the component adds a drag-and-drop column to each row. If you don't need this feature use the drag=false attribute:

<list-view id="two" drag="false">
  <span width="2fr">one</span>
  <span width="1fr">two</span>

Simple List without Header Section

To hide the "headers" section of the view, use headers=false attribute:

<list-view id="two" drag="false" headers="false">
  <span width="2fr">one</span>
  <span width="1fr">two</span>


Username Title


Use the CSS "--height" and "--gap" values to control the height of rows and the gap between columns. Also you can use multiple="false" attribute to disable the multiple selection feature.

<list-view style="--height: 32px; --gap: 5px;">
  <span width="32px"></span>
  <span width="1fr">Title</span>

In case you need to inject CSS to further customize the look and behavior of the element, create your custom element by extending this element:

class ExtenededListView extends SimpleListView {

  /* inject */
  css(styles) {
    if (!this.#style) {
      const style = this.#style = document.createElement('style');

    this.#style.textContent = styles;
customElements.define('extended-list-view', ExtenededListView);

Updating a Row

Since a row has many DOM elements, to update it you need to alter the internal elements by accessing the option._interal object.



for (const option of c.selectedOptions) {
  option._internal.option.name = value;
  option._internal.option.value = value;
  option._internal.div.children[1].textContent = value;