Skip to content

Instantly share code, notes, and snippets.

@alice
Last active May 3, 2020 23:41
Show Gist options
  • Save alice/bac0f6741b852f6e87f53e028efbde2f to your computer and use it in GitHub Desktop.
Save alice/bac0f6741b852f6e87f53e028efbde2f to your computer and use it in GitHub Desktop.
<custom-listbox>
  <custom-option>One</custom-option>
  <custom-option>Two</custom-option>
  <custom-option>Three</custom-option>
</custom-listbox>
class CustomOption extends HTMLElement {
  constructor() {
    super();

    this._internals = this.attachInternals();
    this._internals.role = "option";
    this._internals.focusability = "default";  // or "unfocusable"? or `false`?

    this._selected = false;
    this._internals.ariaSelected = "false";
    
    // Add event listeners here
  }
  
  connectedCallback() {
    this._listbox = this.parentElement;
  }

  onClick(event) {
    this.setSelected(true);
    this.focus();
  }

  setSelected(selected) {
    if (this._selected == selected)
      return;

    this._selected = selected;
    this._internals.ariaSelected = String(selected);
    this._internals.focusability = "auto";  // or "focusable"? Or `true`?
    this._listbox.setSelectedOption(this);
  }
}

class CustomListbox extends HTMLElement {
  constructor() {
    super();

    this._internals = this.attachInternals();
    this._internals.focusability = "auto";
    this._selectedOption = null;
    
    // Add event listeners here
  }

  setSelectedOption(optionElement) {
    if (this._selectedOption === optionElement)
      return;

    if (this._selectedOption !== null) {
      // Make previously selected option unfocusable
      this._selectedOption.setSelected(false);
    }

    this._selectedOption = optionElement;

    if (this._selectedOption === null) {
      this._internals.focusability = "auto";  // or "focusable"? or `true`?
      return;
    }
    
    this._internals.focusability = "default";  // or "unfocusable"? or `false`?

    // Ensure calling this method directly sets up the right state
    this._selectedOption.setSelected(true);
  }
  
  // keyboard event handling goes here - keyboard events bubble up from options
  // up arrow => setSelectedOption(previousOption) or no-op if at start
  // down arrow => setSelectedOption(nextOption) or no-op if at end
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment