Bug 1752532 Comment 9 Edit History

Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.

I did some research into what we'll need from the tree or listbox elements eventually, and I've come up with a semi-detailed plan. This will also address bug 1751978. Anyone interested, please read the details below and give feedback.

## (Multi-)Selectable widgets

Trees and listboxes are widgets whose items can be selected, sometimes multiple items can be selected. Another example of a widget that allows multi-selection is the recipient pills in the compose window.

All these should share the same focus and selection controls. I'm going to base this off the current XUL:tree controls.

### Multi-selection and focus model

This is a "selection follows focus, by default" model. In the following "Click" is a primary button click. We assume the widget has a vertical layout for now.

Focus is controlled by:

+ Click: Focus the clicked item.
+ UpArrow: Move focus to previous item, if there is one.
+ DownArrow, Home, End: Same as above, except move focus to the next item, first item and last item, respectively.

How this changes the selection is controlled by modifiers:

+ No modifiers: Only the newly focused item is selected, and everything else is unselected.
+ Ctrl: If clicking, this toggles the selection state of the newly focused item. If using arrow keys, it leaves the selection state unchanged. Instead, Ctrl+Space will toggle the selection state of the focused item.
+ Shift: Select all the items between the newly focused item and a "selection origin" item, and nothing else. If the "selection origin" item is cleared, we use the previously focused item or 0. This "selection origin" is cleared whenever the selection state of an item is changed by some other method.

If the list is a tree with collapsable child items, then we have additional controls:

+ RightArrow or LeftArrow. This will try to expand or collapse the focused item, depending on the display direction. Expanded (or collapsed) items are unselected. If this would collapse the focused item, but it is already collapsed or cannot be collapsed, then focus is moved to the parent instead and the selection is changed to just the parent (regardless of modifiers). Similarly, it may move focus to the first child if it cannot be expanded.
+ Clicking a twisty icon does the same on the clicked item. This replaces the above focus and selection behaviour. In particular, focus is *not* moved to the item.

Some further controls that seem to be common:

+ Context menu: If the clicked or focused item is selected, do nothing special. Otherwise, temporarily only select the single item, and restore the old selection when the context menu closes.
+ Delete: Delete the selected items. I feel like an exception should be made when the focused item is not part of the selection.

Finally, if the widget is layed out horizontally, then we swap the vertical arrow keys for horizontal arrow keys.

### Alternative behaviour

#### GTK

I also tested the default controls for gtk4's tree views, and it has similar behaviour except the "selection origin" item is initially set to the last item that was selected or unselected. Moreover, the expand/collapse controls require the Shift modifier.

#### WAI-ARIA recommended

The model differs from the "Recommended selection model" on https://www.w3.org/TR/wai-aria-practices/#listbox_kbd_interaction . Specifically, the recommended model does not require a modifier to be pressed in order to do multi-selection. However, this means that selection does not follow focus by default. In most situations in thunderbird, even though multi-selection may be possible, the primary usage is single-selection, and it is mostly sufficient. In these cases, I think the selection following the focus is more desirable.

However, if there are widgets where mutli-selection is the primary usage, or "selection follows focus" is inappropriate, then the above model should **not** be used. Instead, selection should be unchanged with moving focus, and be toggled with "Space". I can't think of an example in thunderbird where this would be the case though.

Note that the model defined above is similar to the "Alternative selection model" defined in the link. The main difference is

> + Shift + Down Arrow: Moves focus to and toggles the selection state of the next option.

This doesn't make much sense to me because if you start focused on a single selected item and press Shift+Down,Shift+Down,Shift+Up, then you end up with "selected, un-selected, selected", rather than "selected, selected, un-selected". I feel like this isn't the intended behaviour.

### How to implement this.

The above behaviour is fairly complex, and still doesn't cover every detail. It also gets more complicated if we need to ensure that at least one item is always selected. So I wouldn't want each widget with multi-selection behaviour to re-implement this, and they could diverge. For example, XUL richlistbox has similar controls to XUL tree, but there are edge cases that cause them to differ (probably a bug). Therefore, I would like all these widgets to share some common code.

The main complication to sharing code is that it would have to work with `TreeViewListbox`. I think a shared class doesn't make sense because I wouldn't want each widget to have to share public methods, or have to distinguish between private and "protected" methods.

Instead, I think a common interface or trait-like class makes more sense. E.g. something like

```js
class SelectionWidgetController {
  constructor(methdos) {
    this.#methods = methods;
  }

  handleEvent(event) {
    if (event.type == "click") {
      let clickedIndex = this.#methods.getIndexFromClickTarget(event.target);
      this.#methods.setFocusItem(clickedIndex);
      /* ... */
    }
  }
}

class TreeViewListbox {
  connectedCallback() {
    /* ... */
    let this.#selectionWidgetController = new SelectionWidgetController({
      getIndexFromClickTarget: node => /* ... */,
      setFocusItem: index => /* ... */,
      /* ... */
    });
    this.addEventListner("click", event => this.#selectionWidgetController.handleEvent(event))
  }
}
```

Obviously it would be more complicated than this, and I might end up shifting more into the `SelectionWidgetController` to avoid boilerplate. But the general idea is that `SelectionWidgetController` itself would hold almost no data on the tree or list composition, but would track items using an index and use the provided methods to find out what it needs to. This means that it won't scale with the number of rows. Basically, it would be similar to `nsITreeSelection` but would also control focus, handle events, and it would be independent of both `nsITreeView` and the widget.

I'm not 100% set on this approach, and it is not particularly "elegant" within javascript. So if anyone knows of a better approach, let me know.

## Specific widgets

### Long lists or trees

When performance is an issue, not every entry needs a corresponding element. As such, we cannot replicate the tree or list data in the DOM tree, so we need to use `aria-level`, `aria-setsize` and `aria-posinset` (see comment 6) to convey this information. Basically, I'm going to modify `TreeViewListbox`:

+ Add a means to select whether the role of the widget is a `listbox` or a `treegrid` (and maybe `tree` if we ever need it).
+ We need to ensure that the focused item is never removed from the DOM. Right now, if you scroll then the tree will loose track of the focused element as it goes out of view. We need to keep it present in the appropriate place.
+ Drop the `nsITreeSelection`. Otherwise this will duplicate what the `SelectionWidgetController` is already tracking. We'll need to ensure that the `nsITreeView`s in use request this selection information through the widget itself. Hopefully this'll also help address the current three-way-entangled nature of `nsITreeView`, `nsITreeSelection` and the tree widget, and this should make it easier to replace `nsITreeView` in the future.
+ I might rename it to something else since the name is a bit confusing. I would like just `TreeView`, but it is kind of taken by `nsITreeView`, so maybe I'll choose `TreeDisplay` or `TreeViewWidget` or `TreeViewElement`.

### Other lists and trees.

For other elements, I think overall we should prefer using the DOM structuring to imply semantic relations, rather than relying on `aria-level`, `aria-setsize` and `aria-posinset`. This covers all the elements that currently use the `TreeListboxMixin` class constructor.

I'm planning on making bigger changes to these. I'm going to make them more opaque and stricter about structuring. My general aim is to make these simple for a developer to use (less effort than setting up an `nsITreeView`), and hard for them to make mistakes if they stick to the public methods.

Overall, I think we'll need three distinct structures.

#### 1. Basic lists.

Most of the time, where we would have used a XUL richlistbox, we can instead use

```html
<ul is="selection-list" role="listbox">
  <li role="option"><!--Item--></li>
</ul>
```

This structure would be enforced within the class itself, rather than for each usage (as is done now), instead a developer would use a public "API" to add an item (they provide what goes into `<!--Item-->` above), remove an item, etc.

For lists that can be reordered, we need a live region to inform a screen reader user of the reordering that has taken place. E.g.

```html
<span aria-live="polite">Moved to position 2</span>
```

Also, since there are no standard keyboard controls for reordering, we also need to expose another way to reorder the selected item. E.g. in the account settings tree, a menuitem in the account actions menu with "move account up" and another for "move account down".

#### 2. Grouped lists.

For lists whose items are grouped under headings, we can basically use a tree with depth 2, where the depth-0 items are non-focusable headings. But we can still expose it as a `listbox`:

```html
<ul is="grouped-list" role=listbox">
  <li role="none">
    <span id="heading1"><!--Group heading--></span>
    <ul role="group" aria-labeledby="heading1">
      <li role="option"><!--Item--></li>
    </ul>
  </li>
</ul>
```

This would be used in a few places. Currently it would be used in the agenda list (where the headings are the dates). In the future we might use it in the multiday views with the events grouped by all-day and not-all-day.

#### 3. Trees

For basic trees, which are normally used for navigation, we can use the following structure.

```html
<ul is="selection-tree" role="tree">
  <li role="treeitem">
    <img src="twisty" alt=""/><span><!--Parent--></span>
    <ul role="group" aria-expanded="true">
      <li role="treeitem"><!--Leaf--></li>
    </ul>
  </li>
</ul>
```

In particular, the "twisty" icon would be owned and controlled by the class, rather than per usage.

## Method and Priorities

Rather than try and replace `TreeListboxMixin` in a single patch, I'm going to create these other widgets along side it and then one-by-one convert widgets from `TreeListboxMixin` to the new widgets. Once this is complete, `TreeListboxMixin` will be removed.

I'm going to prioritise the widgets that are needed in the new addressbook tab:

+ A list view for the list of contacts. This can be very long, so would use the modified `TreeViewListbox` with `role="listbox"`.
+ A tree widget for the list of addressbooks and mailing lists. This will require a basic single-select non-reorderable tree widget.
I did some research into what we'll need from the tree or listbox elements eventually, and I've come up with a semi-detailed plan. This will also address bug 1751978. Anyone interested, please read the details below and give feedback.

## (Multi-)Selectable widgets

Trees and listboxes are widgets whose items can be selected, sometimes multiple items can be selected. Another example of a widget that allows multi-selection is the recipient pills in the compose window.

All these should share the same focus and selection controls. I'm going to base this off the current XUL:tree controls.

### Multi-selection and focus model

This is a "selection follows focus, by default" model. In the following "Click" is a primary button click. We assume the widget has a vertical layout for now.

Focus is controlled by:

+ Click: Focus the clicked item.
+ UpArrow: Move focus to previous item, if there is one.
+ DownArrow, Home, End: Same as above, except move focus to the next item, first item and last item, respectively.

How this changes the selection is controlled by modifiers:

+ No modifiers: Only the newly focused item is selected, and everything else is unselected.
+ Ctrl: If clicking, this toggles the selection state of the newly focused item. If using arrow keys, it leaves the selection state unchanged. Instead, Ctrl+Space will toggle the selection state of the focused item.
+ Shift: Select all the items between the newly focused item and a "selection origin" item, and nothing else. If the "selection origin" item is cleared, we use the previously focused item or 0. This "selection origin" is cleared whenever the selection state of an item is changed by some other method.

If the list is a tree with collapsable child items, then we have additional controls:

+ RightArrow or LeftArrow. This will try to expand or collapse the focused item, depending on the display direction. Expanded (or collapsed) items are unselected. If this would collapse the focused item, but it is already collapsed or cannot be collapsed, then focus is moved to the parent instead and the selection is changed to just the parent (regardless of modifiers). Similarly, it may move focus to the first child if it cannot be expanded.
+ Clicking a twisty icon does the same on the clicked item. This replaces the above focus and selection behaviour. In particular, focus is *not* moved to the item.

Some further controls that seem to be common:

+ Context menu: If the clicked or focused item is selected, do nothing special. Otherwise, temporarily only select the single item, and restore the old selection when the context menu closes.
+ Delete: Delete the selected items. I feel like an exception should be made when the focused item is not part of the selection.

Finally, if the widget is layed out horizontally, then we swap the vertical arrow keys for horizontal arrow keys.

### Alternative behaviour

#### GTK

I also tested the default controls for gtk4's tree views, and it has similar behaviour except the "selection origin" item is initially set to the last item that was selected or unselected. Moreover, the expand/collapse controls require the Shift modifier.

#### WAI-ARIA recommended

The model differs from the "Recommended selection model" on https://www.w3.org/TR/wai-aria-practices/#listbox_kbd_interaction . Specifically, the recommended model does not require a modifier to be pressed in order to do multi-selection. However, this means that selection does not follow focus by default. In most situations in thunderbird, even though multi-selection may be possible, the primary usage is single-selection, and it is mostly sufficient. In these cases, I think the selection following the focus is more desirable.

However, if there are widgets where mutli-selection is the primary usage, or "selection follows focus" is inappropriate, then the above model should **not** be used. Instead, selection should be unchanged with moving focus, and be toggled with "Space". I can't think of an example in thunderbird where this would be the case though.

Note that the model defined above is similar to the "Alternative selection model" defined in the link. The main difference is

> + Shift + Down Arrow: Moves focus to and toggles the selection state of the next option.

This doesn't make much sense to me because if you start focused on a single selected item and press Shift+Down,Shift+Down,Shift+Up, then you end up with "selected, un-selected, selected", rather than "selected, selected, un-selected". I feel like this isn't the intended behaviour.

### Implementation

The above behaviour is fairly complex, and still doesn't cover every detail. It also gets more complicated if we need to ensure that at least one item is always selected. So I wouldn't want each widget with multi-selection behaviour to re-implement this, and they could diverge. For example, XUL richlistbox has similar controls to XUL tree, but there are edge cases that cause them to differ (probably a bug). Therefore, I would like all these widgets to share some common code.

The main complication to sharing code is that it would have to work with `TreeViewListbox`. I think a shared class doesn't make sense because I wouldn't want each widget to have to share public methods, or have to distinguish between private and "protected" methods.

Instead, I think a common interface or trait-like class makes more sense. E.g. something like

```js
class SelectionWidgetController {
  constructor(methdos) {
    this.#methods = methods;
  }

  handleEvent(event) {
    if (event.type == "click") {
      let clickedIndex = this.#methods.getIndexFromClickTarget(event.target);
      this.#methods.setFocusItem(clickedIndex);
      /* ... */
    }
  }
}

class TreeViewListbox {
  connectedCallback() {
    /* ... */
    let this.#selectionWidgetController = new SelectionWidgetController({
      getIndexFromClickTarget: node => /* ... */,
      setFocusItem: index => /* ... */,
      /* ... */
    });
    this.addEventListner("click", event => this.#selectionWidgetController.handleEvent(event))
  }
}
```

Obviously it would be more complicated than this, and I might end up shifting more into the `SelectionWidgetController` to avoid boilerplate. But the general idea is that `SelectionWidgetController` itself would hold almost no data on the tree or list composition, but would track items using an index and use the provided methods to find out what it needs to. This means that it won't scale with the number of rows. Basically, it would be similar to `nsITreeSelection` but would also control focus, handle events, and it would be independent of both `nsITreeView` and the widget.

I'm not 100% set on this approach, and it is not particularly "elegant" within javascript. So if anyone knows of a better approach, let me know.

## Specific widgets

### Long lists or trees

When performance is an issue, not every entry needs a corresponding element. As such, we cannot replicate the tree or list data in the DOM tree, so we need to use `aria-level`, `aria-setsize` and `aria-posinset` (see comment 6) to convey this information. Basically, I'm going to modify `TreeViewListbox`:

+ Add a means to select whether the role of the widget is a `listbox` or a `treegrid` (and maybe `tree` if we ever need it).
+ We need to ensure that the focused item is never removed from the DOM. Right now, if you scroll then the tree will loose track of the focused element as it goes out of view. We need to keep it present in the appropriate place.
+ Drop the `nsITreeSelection`. Otherwise this will duplicate what the `SelectionWidgetController` is already tracking. We'll need to ensure that the `nsITreeView`s in use request this selection information through the widget itself. Hopefully this'll also help address the current three-way-entangled nature of `nsITreeView`, `nsITreeSelection` and the tree widget, and this should make it easier to replace `nsITreeView` in the future.
+ I might rename it to something else since the name is a bit confusing. I would like just `TreeView`, but it is kind of taken by `nsITreeView`, so maybe I'll choose `TreeDisplay` or `TreeViewWidget` or `TreeViewElement`.

### Other lists and trees.

For other elements, I think overall we should prefer using the DOM structuring to imply semantic relations, rather than relying on `aria-level`, `aria-setsize` and `aria-posinset`. This covers all the elements that currently use the `TreeListboxMixin` class constructor.

I'm planning on making bigger changes to these. I'm going to make them more opaque and stricter about structuring. My general aim is to make these simple for a developer to use (less effort than setting up an `nsITreeView`), and hard for them to make mistakes if they stick to the public methods.

Overall, I think we'll need three distinct structures.

#### 1. Basic lists.

Most of the time, where we would have used a XUL richlistbox, we can instead use

```html
<ul is="selection-list" role="listbox">
  <li role="option"><!--Item--></li>
</ul>
```

This structure would be enforced within the class itself, rather than for each usage (as is done now), instead a developer would use a public "API" to add an item (they provide what goes into `<!--Item-->` above), remove an item, etc.

For lists that can be reordered, we need a live region to inform a screen reader user of the reordering that has taken place. E.g.

```html
<span aria-live="polite">Moved to position 2</span>
```

Also, since there are no standard keyboard controls for reordering, we also need to expose another way to reorder the selected item. E.g. in the account settings tree, a menuitem in the account actions menu with "move account up" and another for "move account down".

#### 2. Grouped lists.

For lists whose items are grouped under headings, we can basically use a tree with depth 2, where the depth-0 items are non-focusable headings. But we can still expose it as a `listbox`:

```html
<ul is="grouped-list" role=listbox">
  <li role="none">
    <span id="heading1"><!--Group heading--></span>
    <ul role="group" aria-labeledby="heading1">
      <li role="option"><!--Item--></li>
    </ul>
  </li>
</ul>
```

This would be used in a few places. Currently it would be used in the agenda list (where the headings are the dates). In the future we might use it in the multiday views with the events grouped by all-day and not-all-day.

#### 3. Trees

For basic trees, which are normally used for navigation, we can use the following structure.

```html
<ul is="selection-tree" role="tree">
  <li role="treeitem">
    <img src="twisty" alt=""/><span><!--Parent--></span>
    <ul role="group" aria-expanded="true">
      <li role="treeitem"><!--Leaf--></li>
    </ul>
  </li>
</ul>
```

In particular, the "twisty" icon would be owned and controlled by the class, rather than per usage.

## Method and Priorities

Rather than try and replace `TreeListboxMixin` in a single patch, I'm going to create these other widgets along side it and then one-by-one convert widgets from `TreeListboxMixin` to the new widgets. Once this is complete, `TreeListboxMixin` will be removed.

I'm going to prioritise the widgets that are needed in the new addressbook tab:

+ A list view for the list of contacts. This can be very long, so would use the modified `TreeViewListbox` with `role="listbox"`.
+ A tree widget for the list of addressbooks and mailing lists. This will require a basic single-select non-reorderable tree widget.
I did some research into what we'll need from the tree or listbox elements eventually, and I've come up with a semi-detailed plan. This will also address bug 1751978. Anyone interested, please read the details below and give feedback.

## (Multi-)Selectable widgets

Trees and listboxes are widgets whose items can be selected, sometimes multiple items can be selected. Another example of a widget that allows multi-selection is the recipient pills in the compose window.

All these should share the same focus and selection controls. I'm going to base this off the current XUL:tree controls.

### Multi-selection and focus model

This is a "selection follows focus, by default" model. In the following "Click" is a primary button click. We assume the widget has a vertical layout for now.

Focus is controlled by:

+ Click: Focus the clicked item.
+ UpArrow: Move focus to previous item, if there is one.
+ DownArrow, Home, End: Same as above, except move focus to the next item, first item and last item, respectively.

How this changes the selection is controlled by modifiers:

+ No modifiers: Only the newly focused item is selected, and everything else is unselected.
+ Ctrl: If clicking, this toggles the selection state of the newly focused item. If using arrow keys, it leaves the selection state unchanged. Instead, Ctrl+Space will toggle the selection state of the focused item.
+ Shift: Select all the items between the newly focused item and a "selection origin" item, and nothing else. If the "selection origin" item is cleared, we use the previously focused item or the first item. This "selection origin" is cleared whenever the selection state of an item is changed by some other method.

If the list is a tree with collapsable child items, then we have additional controls:

+ RightArrow or LeftArrow. This will try to expand or collapse the focused item, depending on the display direction. Expanded (or collapsed) items are unselected. If this would collapse the focused item, but it is already collapsed or cannot be collapsed, then focus is moved to the parent instead and the selection is changed to just the parent (regardless of modifiers). Similarly, it may move focus to the first child if it cannot be expanded.
+ Clicking a twisty icon does the same on the clicked item. This replaces the above focus and selection behaviour. In particular, focus is *not* moved to the item.

Some further controls that seem to be common:

+ Context menu: If the clicked or focused item is selected, do nothing special. Otherwise, temporarily only select the single item, and restore the old selection when the context menu closes.
+ Delete: Delete the selected items. I feel like an exception should be made when the focused item is not part of the selection.

Finally, if the widget is layed out horizontally, then we swap the vertical arrow keys for horizontal arrow keys.

### Alternative behaviour

#### GTK

I also tested the default controls for gtk4's tree views, and it has similar behaviour except the "selection origin" item is initially set to the last item that was selected or unselected. Moreover, the expand/collapse controls require the Shift modifier.

#### WAI-ARIA recommended

The model differs from the "Recommended selection model" on https://www.w3.org/TR/wai-aria-practices/#listbox_kbd_interaction . Specifically, the recommended model does not require a modifier to be pressed in order to do multi-selection. However, this means that selection does not follow focus by default. In most situations in thunderbird, even though multi-selection may be possible, the primary usage is single-selection, and it is mostly sufficient. In these cases, I think the selection following the focus is more desirable.

However, if there are widgets where mutli-selection is the primary usage, or "selection follows focus" is inappropriate, then the above model should **not** be used. Instead, selection should be unchanged with moving focus, and be toggled with "Space". I can't think of an example in thunderbird where this would be the case though.

Note that the model defined above is similar to the "Alternative selection model" defined in the link. The main difference is

> + Shift + Down Arrow: Moves focus to and toggles the selection state of the next option.

This doesn't make much sense to me because if you start focused on a single selected item and press Shift+Down,Shift+Down,Shift+Up, then you end up with "selected, un-selected, selected", rather than "selected, selected, un-selected". I feel like this isn't the intended behaviour.

### Implementation

The above behaviour is fairly complex, and still doesn't cover every detail. It also gets more complicated if we need to ensure that at least one item is always selected. So I wouldn't want each widget with multi-selection behaviour to re-implement this, and they could diverge. For example, XUL richlistbox has similar controls to XUL tree, but there are edge cases that cause them to differ (probably a bug). Therefore, I would like all these widgets to share some common code.

The main complication to sharing code is that it would have to work with `TreeViewListbox`. I think a shared class doesn't make sense because I wouldn't want each widget to have to share public methods, or have to distinguish between private and "protected" methods.

Instead, I think a common interface or trait-like class makes more sense. E.g. something like

```js
class SelectionWidgetController {
  constructor(methdos) {
    this.#methods = methods;
  }

  handleEvent(event) {
    if (event.type == "click") {
      let clickedIndex = this.#methods.getIndexFromClickTarget(event.target);
      this.#methods.setFocusItem(clickedIndex);
      /* ... */
    }
  }
}

class TreeViewListbox {
  connectedCallback() {
    /* ... */
    let this.#selectionWidgetController = new SelectionWidgetController({
      getIndexFromClickTarget: node => /* ... */,
      setFocusItem: index => /* ... */,
      /* ... */
    });
    this.addEventListner("click", event => this.#selectionWidgetController.handleEvent(event))
  }
}
```

Obviously it would be more complicated than this, and I might end up shifting more into the `SelectionWidgetController` to avoid boilerplate. But the general idea is that `SelectionWidgetController` itself would hold almost no data on the tree or list composition, but would track items using an index and use the provided methods to find out what it needs to. This means that it won't scale with the number of rows. Basically, it would be similar to `nsITreeSelection` but would also control focus, handle events, and it would be independent of both `nsITreeView` and the widget.

I'm not 100% set on this approach, and it is not particularly "elegant" within javascript. So if anyone knows of a better approach, let me know.

## Specific widgets

### Long lists or trees

When performance is an issue, not every entry needs a corresponding element. As such, we cannot replicate the tree or list data in the DOM tree, so we need to use `aria-level`, `aria-setsize` and `aria-posinset` (see comment 6) to convey this information. Basically, I'm going to modify `TreeViewListbox`:

+ Add a means to select whether the role of the widget is a `listbox` or a `treegrid` (and maybe `tree` if we ever need it).
+ We need to ensure that the focused item is never removed from the DOM. Right now, if you scroll then the tree will loose track of the focused element as it goes out of view. We need to keep it present in the appropriate place.
+ Drop the `nsITreeSelection`. Otherwise this will duplicate what the `SelectionWidgetController` is already tracking. We'll need to ensure that the `nsITreeView`s in use request this selection information through the widget itself. Hopefully this'll also help address the current three-way-entangled nature of `nsITreeView`, `nsITreeSelection` and the tree widget, and this should make it easier to replace `nsITreeView` in the future.
+ I might rename it to something else since the name is a bit confusing. I would like just `TreeView`, but it is kind of taken by `nsITreeView`, so maybe I'll choose `TreeDisplay` or `TreeViewWidget` or `TreeViewElement`.

### Other lists and trees.

For other elements, I think overall we should prefer using the DOM structuring to imply semantic relations, rather than relying on `aria-level`, `aria-setsize` and `aria-posinset`. This covers all the elements that currently use the `TreeListboxMixin` class constructor.

I'm planning on making bigger changes to these. I'm going to make them more opaque and stricter about structuring. My general aim is to make these simple for a developer to use (less effort than setting up an `nsITreeView`), and hard for them to make mistakes if they stick to the public methods.

Overall, I think we'll need three distinct structures.

#### 1. Basic lists.

Most of the time, where we would have used a XUL richlistbox, we can instead use

```html
<ul is="selection-list" role="listbox">
  <li role="option"><!--Item--></li>
</ul>
```

This structure would be enforced within the class itself, rather than for each usage (as is done now), instead a developer would use a public "API" to add an item (they provide what goes into `<!--Item-->` above), remove an item, etc.

For lists that can be reordered, we need a live region to inform a screen reader user of the reordering that has taken place. E.g.

```html
<span aria-live="polite">Moved to position 2</span>
```

Also, since there are no standard keyboard controls for reordering, we also need to expose another way to reorder the selected item. E.g. in the account settings tree, a menuitem in the account actions menu with "move account up" and another for "move account down".

#### 2. Grouped lists.

For lists whose items are grouped under headings, we can basically use a tree with depth 2, where the depth-0 items are non-focusable headings. But we can still expose it as a `listbox`:

```html
<ul is="grouped-list" role=listbox">
  <li role="none">
    <span id="heading1"><!--Group heading--></span>
    <ul role="group" aria-labeledby="heading1">
      <li role="option"><!--Item--></li>
    </ul>
  </li>
</ul>
```

This would be used in a few places. Currently it would be used in the agenda list (where the headings are the dates). In the future we might use it in the multiday views with the events grouped by all-day and not-all-day.

#### 3. Trees

For basic trees, which are normally used for navigation, we can use the following structure.

```html
<ul is="selection-tree" role="tree">
  <li role="treeitem">
    <img src="twisty" alt=""/><span><!--Parent--></span>
    <ul role="group" aria-expanded="true">
      <li role="treeitem"><!--Leaf--></li>
    </ul>
  </li>
</ul>
```

In particular, the "twisty" icon would be owned and controlled by the class, rather than per usage.

## Method and Priorities

Rather than try and replace `TreeListboxMixin` in a single patch, I'm going to create these other widgets along side it and then one-by-one convert widgets from `TreeListboxMixin` to the new widgets. Once this is complete, `TreeListboxMixin` will be removed.

I'm going to prioritise the widgets that are needed in the new addressbook tab:

+ A list view for the list of contacts. This can be very long, so would use the modified `TreeViewListbox` with `role="listbox"`.
+ A tree widget for the list of addressbooks and mailing lists. This will require a basic single-select non-reorderable tree widget.

Back to Bug 1752532 Comment 9