-
Notifications
You must be signed in to change notification settings - Fork 4
Tree Specification
-
3.3 Globalization/Localization
3.5 API
Team Name: Astrea
Developer Name: Martin Evtimov, Monika Kirkova
Designer Name: Marin Popov
- Peer Developer Name | Date:
- Design Manager Stefan Ivanov| Date: 19 Jan 2022
- Radoslav Mirchev| Date:2022-05-20
- Radoslav Karaivanov | Date: 2022-05-19
Version | Users | Date | Notes |
---|---|---|---|
1 |
The <igc-tree>
allows users to represent hierarchical data in a tree-view structure, maintaining parent-child relationships, as well as to define static tree-view structure without a corresponding data model.
<igc-tree>
${data.map((x) => html`
<igc-tree-item .value=${x} .expanded=${x.expanded} .selected=${x.selected} .label=${x.value}>
${x.children.map((y) => html`
<igc-tree-item .value=${y} .expanded=${y.expanded} .selected=${y.selected}>
<img slot="label" src=${y.image} alt=${y.imageAlt}>
</igc-tree-item>
`
</igc-tree-item>
`
</igc-tree>
The <igc-tree>
should primarily be used as a navigational component when visualizing a nested data structure. The control is not data-bound and takes a declarative approach, giving users more control over what is being rendered.
The tree should have the following features out-of-the-box
- Rendering nested items in a hierarchical fashion, maintaining a parent-child relationship
- Expanding and collapsing items, so all crucial information can be clearly visible at all times
- Disabled items which do not support any user interaction (e.g. permission-based tree view)
- Active items - a node marked as "active" is highlighted w/ a specific style (e.g. the current location on a site map)
- Selection
- 5.1. None - no selection through user input. API selection manipulation is still possible
- 5.2. Multiple - each item has a checkbox through which it can be selected via user input. Each item has two states - selected or not. Supports multiple selection.
- 5.3. Cascade - selecting an item selects its child items. Partially selected collections mark the resp. items as indeterminate.
- Keyboard navigation, supporting all of the previously mention features
- Accessibility features - all items should have proper aria roles and be fully readable and traversable via screen readers
Developer stories:
- Story 1: As a developer, I want to be able to easily create a tree view declaring the item hierarchy.
- Story 2: As a developer, I want to have full control over an item's content, as well as its child items (declarative approach).
- Story 3: As a developer, I want to have an easy way to find an item inside of the control with out-of-the-box API.
- Story 4: As a developer, I want to expand/collapse one or more items programmatically.
- Story 5: As a developer, I want to enable/disable the selection of a single item.
- Story 6: As a developer, I want to enable/disable the selection of multiple items.
- Story 7: As a developer, I want to enable/disable cascade selection of items so that selecting an item, selects all items in the tree below it as well and the state of each item reflects the cumulative one of its children.
- Story 8: As a developer, I want to set an item's selection state programmatically.
- Story 9: As a developer, I want to set an item's selection state programmatically, even when selection through user interaction is disabled.
- Story 10: As a developer, I want to be able to perform custom handling on user interaction - item selection, expansion/collapsing.
- Story 11: As a developer, I want to be able to ensure accessibility e.g. via proper
aria
roles in different cases. - Story 12: As a developer, I want to be able to mark items as disabled, so they are ignored in user interaction.
- Story 13: As a developer, I want to mark an item as the tree's active item, styling it in a pre-defined way and marking it as a point of interest to the users.
- Story 14: As a developer, I want to be able to distinguish when the active item changes through user interaction.
- Story 15: As a developer, I want to be able to bind an item's expansion state to a data model and ensure consistency between the two.
- Story 16: As a developer, I want to be able to bind an item's selection state to a data model and ensure consistency between the two.
- Story 17: As a developer, I want to be able to template the expand/collapse indicators for the tree.
- Story 18: As a developer, I want to be able to specify how many expanded sibling items there can be (
singleBranchExpand
input). - Story 19: As a developer, I want to be able to specify if nodes could be expanded/collapsed when clicking over them (
toggleNodeOnClick
input).
End-user stories:
The tree should allow me, as an end-user, to understand the relationships between the various items and use it to navigate the hierarchy of content.
- Story 1: As an end-user, I want to have the items organized in a clear hierarchy, so that I can understand their relationship with one another.
- Story 2: As an end-user, I want to have the items organized in a clear hierarchy, so that I can easily expand/collapse them to get to the items I am looking for.
- Story 3: As an end-user, I want to be able to expand/collapse items, so that I can create a state with the most viable information for me on my screen.
- Story 4: As an end-user, I want to have a clear indication of the active item, so that I have a better understanding of the information I'm looking at on the rest of my screen.
- Story 5: As an end-user, I want to have a clear indication if some/all/none of the child items of a given item are selected, so that I have a clear understanding of the current selection of items.
- Story 6: As an end-user, I want to select a single item, so that I navigate to the content it offers.
- Story 7: As an end-user, I want to select multiple items, so that I can perform an operation on all of them at once.
- Story 8: As an end-user, I want to have a cascade selection of a parent item implicitly selecting all of its children, grandchildren, etc., so that I can perform an operation on all of them at once.
- Story 9: As an end-user, I want to be able to quickly expand/collapse/select an item with a mouse and keyboard, so that I have a variety of convenient ways to interact with the hierarchy.
Describe behavior, design, look and feel of the implemented feature. Always include visual mock-up
The IgcTreeComponent
should support the three display sizes available for other components - 'small'
, 'medium'
and 'large'
(default). They come with distinct item heights and padding.
** All use cases and variants above are also available for hand-off
Developers are able to declare the tree and its items by specifying the item hierarchy and iterating through a data set:
<!-- Standard example -->
<igc-tree>
${data.map((x) => html`
<igc-tree-item .value=${x} .expanded=${x.expanded} .selected=${x.selected} .label=${x.value}>
${x.children.map((y) => html`
<igc-tree-item .value=${y} .expanded=${y.expanded} .selected=${y.selected}>
<img slot="label" src=${y.image} alt=${y.imageAlt}>
</igc-tree-item>
`
</igc-tree-item>
`
</igc-tree>
When a node should render a link, button or some tabbable element, enable the tree hasFocusableContent prop. This will make sure the proper aria
role
is assigned to the node's DOM
elements.
<igc-tree hasFocusableContent>
<igc-tree-item>
<p slot="label">
<a href="https://www.infragistics.com/" target="_blank">Infragistics</a>
</p>
</igc-tree-item>
</igc-tree>
To render a tree you do not necessarily need a data set - developers can create individual items w/o binding them to data:
<!-- Simple example with hardcoded items -->
<igc-tree .selection="multiple">
<igc-tree-item expanded>
<div slot="label">
I am a parent item 1
<img src="hard_coded_src.webb" alt="Alt Text">
</div>
<igc-tree-item expanded .label="I am a child item 1">
</igc-tree-item>
</igc-tree-item>
<igc-tree-item selected>
<div slot="label">
I am a parent item 2
<img src="hard_coded_src.webb" alt="Alt Text">
</div>
<igc-tree-item .label="I am a child item 1">
</igc-tree-item>
</igc-tree-item>
</igc-tree>
3.3. Globalization/Localization
Describe any special localization requirements such as the number of localizable strings, regional formats
The keyboard can be used to navigate through all items in the tree.
The control distinguishes two states - focused
and active
.
The focused item is where all events are fired and from where navigation will begin/continue. Focused items are marked with a distinct style.
The active item, in most cases, is the last item on which user interaction took place. Active items also have a distinct style. Active items can be used to better accent an item in that tree that indicates the app's current state (e.g. a current route in the app when using a tree as a navigation component).
In most cases, moving the focused item also moves the active item.
When navigating to items that are outside of view, if the tree (igc-tree
tag) has a scrollbar, scrolls the focused item into view.
If the target item is outside of view AND if the tree (igc-tree
tag) has a scrollbar, scrolls the focused item into view.
When initializing the tree and an item is marked as active, if that item is outside of view AND if the tree (igc-tree
tag) has a scrollbar, scrolls the activated item into view.
FIRST and LAST item refers to the respective visible item WITHOUT expanding/collapsing any existing item.
Disabled items are not counted as visible items for the purpose of keyboard navigation.
Keys | Description | Activates Item |
---|---|---|
ARROW DOWN | Moves to the next visible item. Does nothing if on the LAST tree item. | true |
CTRL + ARROW DOWN | Performs the same as ARROW DOWN. | false |
ARROW UP | Moves to the previous visible item. Does nothing if on the FIRST tree item. | true |
CTRL + ARROW UP | Performs the same as ARROW UP. | false |
TAB | Navigate to the next focusable element on the page* | false |
SHIFT + TAB | Navigate to the previous focusable element on the page* | false |
HOME | Navigates to the FIRST tree item. | true |
END | Navigates to the LAST tree item. | true |
ARROW RIGHT | On an expanded parent item, navigate to the first child of the item. If on a collapsed parent item, expand it. | true |
ARROW LEFT | On an expanded parent item, collapses it. If on a child item, moves to its parent item. | true |
SPACE | Toggles selection of the current tree item. Marks the tree item as active. | true |
* | Expand the tree item and all sibling items on the same level w/ children | true |
CLICK | Focuses the tree item | true |
When selection is enabled, end-user selection of tree items is only allowed through the displayed checkbox. Since both selection types allow multiple selection, the following mouse + keyboard interaction is available:
Combination | Description | Activates Item |
---|---|---|
SHIFT + CLICK / SPACE | when multiple selection is enabled, toggles selection of all tree items between the active one and the one clicked while holding SHIFT. | true |
The tree allows users to represent hierarchical data in a tree-view structure, maintaining parent-child relationships, as well as to define static tree-view structure without a corresponding data model.
Mixins: SizableMixin, EventEmitterMixin
Property | Attribute | Modifiers | Type | Default | Description |
---|---|---|---|---|---|
dir |
dir |
Direction |
"auto" | The direction attribute of the control. | |
items |
readonly | IgcTreeItemComponent[] |
Returns all of the tree's items. | ||
selection |
selection |
"multiple" | "none" | "cascade" |
"none" | The selection state of the tree. | |
singleBranchExpand |
single-branch-expand |
boolean |
false | Whether a single or multiple of a parent's child items can be expanded. | |
toggleNodeOnClick |
toggle-node-on-click |
boolean |
false | Whether clicking over nodes will change their expanded state or not. | |
size |
size |
"small" | "medium" | "large" |
"large" | Determines the size of the component. |
Method | Type | Description |
---|---|---|
collapse |
(items?: IgcTreeItemComponent[] | undefined): void |
Collapses all of the passed items. If no items are passed, collapses ALL items. |
deselect |
(items?: IgcTreeItemComponent[] | undefined): void |
Deselect all items if the items collection is empty. Otherwise, deselect the items in the items collection. |
expand |
(items?: IgcTreeItemComponent[] | undefined): void |
Expands all of the passed items. If no items are passed, expands ALL items. |
select |
(items?: IgcTreeItemComponent[] | undefined): void |
Select all items if the items collection is empty. Otherwise, select the items in the items collection. |
Event | Description |
---|---|
igcItemActivated |
Emitted when the tree's active item changes. |
igcItemCollapsed |
Emitted when tree item is collapsed. |
igcItemCollapsing |
Emitted when tree item is about to collapse. |
igcItemExpanded |
Emitted when tree item is expanded. |
igcItemExpanding |
Emitted when tree item is about to expand. |
igcSelection |
Emitted when item selection is changing, before the selection completes. |
Name | Description |
---|---|
Renders the tree items inside default slot. |
The tree-item component represents a child item of the tree component or another tree item.
Property | Attribute | Modifiers | Type | Default | Description |
---|---|---|---|---|---|
active |
active |
boolean |
false | Marks the item as the tree's active item. | |
disabled |
disabled |
boolean |
false | Get/Set whether the tree item is disabled. Disabled items are ignored for user interactions. | |
expanded |
expanded |
boolean |
false | The tree item expansion state. | |
label |
label |
string |
"" | The tree item label. | |
level |
number |
0 | The depth of the item, relative to the root. | ||
loading |
loading |
boolean |
false | To be used for load-on-demand scenarios in order to specify whether the item is loading data. | |
parent |
IgcTreeItemComponent | null |
null | The parent item of the current tree item (if any) | ||
path |
readonly | IgcTreeItemComponent[] |
The full path to the tree item, starting from the top-most ancestor. | ||
selected |
selected |
boolean |
false | The tree item selection state. | |
tree |
IgcTreeComponent | undefined |
A reference to the tree the item is a part of. | |||
value |
value |
"undefined" | The value entry that the tree item is visualizing. Required for searching through items. |
Method | Type | Description |
---|---|---|
collapse |
(): void |
Collapses the tree item. |
expand |
(): void |
Expands the tree item. |
getChildren |
(options?: { flatten: boolean; }): IgcTreeItemComponent[] |
Returns a collection of child items. If the parameter value is true returns all tree item's direct children, otherwise - only the direct children. |
toggle |
(): void |
Toggles tree item expansion state. |
Name | Description |
---|---|
Renders nested tree-item component. | |
indentation |
Renders the container (by default the space) before the tree item. |
indicator |
Renders the expand indicator container. |
label |
Renders the tree item container. |
loading |
Renders the tree item loading indicator container. |
Part | Description |
---|---|
active |
Indicates an active state. Applies to wrapper . |
focused |
Indicates focused state. Applies to wrapper . |
indicator |
The expand indicator of the tree item. |
label |
The tree item content. |
select |
The checkbox of the tree item when selection is enabled. |
selected |
Indicates selected state. Applies to wrapper . |
text |
The tree item displayed text. |
wrapper |
The wrapper for the tree item. |
Automation
- Should render tree w/ items
- Verify tree item slots are rendered successfully.
- Verify the elements defined in the slots are displayed.
- Should support multiple levels of nesting (igc-tree-item under igc-tree-item)
- Should calculate items'
path
andlevel
correctly, depending on data hierarchy - Should not render collapsed item's children
- Should not render expand indicator if an item has no children
- Should render default indicator for expansion properly depending on item state
- Should render default select marker properly depending on item state
- Should accept custom slot for the tree item expansion indicator
- Should accept custom slot for the tree item indentation area
- Should accept custom slot for the tree item label
- Should accept custom slot for the tree item loading indicator
- Should emit igcActiveItem event when the active item changes through UI
- Should activate the last tree item set as active if there are multiple
- Should scroll to
active
item (when set through API) if the tree has a scrollbar and the item is out of view - Should render items correctly depending on
size
settings -
tree.items
should return all tree items - Should be able to set tree item's
value
andlabel
properties successfully -
item.getChildren({flatten: true})
should return all item's children -
item.getChildren({flatten: false})
should return only the direct children of item - When an item is deleted/added the visible tree items collection should be calculated properly
- Should expand all collapsed (including the disabled) items w/
tree.expand()
- Should expand only specified items w/
tree.expand(item: IgcTreeItemComponent[])
- Should collapse all expanded (including the disabled) items w/
tree.collapse()
- Should collapse only specified items w/
tree.collapse(item: IgcTreeItemComponent[])
- Should collapse items when user interacts w/ indicator and
item.expanded === false
- Should expand items when user interacts w/ indicator and
item.expanded === true
- Should emit
ing
anded
events when item state is toggled through UI - Should collapse items when
item.expanded
is set tofalse
- Should expand items when
item.expanded
is set totrue
- Should expand items when
item.expand()
is called - Should collapse items when
item.collapse()
is called - Should toggle item state when
item.toggle()
is called - Should be able to prevent the expansion through the
ing
events. - Should expand/collapse items when clicking over them if
toggleNodeOnClick === true
- If
singleBranchExpand === true
, should support only one expanded tree item per level. - If
singleBranchExpand === true
anditem.active
is set totrue
, should expand all item to the active one and preserve the state of the other branches. - If
singleBranchExpand === true
and the item is expanded through API, should not collapse the currently expanded items. - Should collapse all items when setting
singleBranchExpand
totrue
and there is no active tree item. - When enabling
singleBranchExpand
and there is an active item, should collapse all tree items except the active item's ancestors.
- Should be able to change selection type to all 3 options ('None' (default), 'Multiple', 'Cascade')
- Should deselect all selected items w/
tree.deselect()
- Should deselect only specified items w/
tree.deselect(item: IgcTreeItemComponent[])
- Should select all deselected items w/
tree.select()
- Should select only specified items w/
tree.select(item: IgcTreeItemComponent[])
- Deleting an item should keep its selection state.
- Should allow setting items as selected through API when
tree.selection === 'None'
- Should not render indicators when
tree.selection === 'None'
- Should select/deselect an item by clicking on the checkbox
- Should emit
igcSelection
event w/ correct args when an item is selected / deselected - Should support multiple selection (e.g. newly selected items do not empty selected collection)
- Should be able to set
item.selected
correctly - Should be able to prevent the
igcSelection
event. - When selecting a range of records using Shift + click key selection of parents should NOT select their children if they are not in the selected range.
- Selecting an item should select its not selected children
- Deselecting selected item should deselect its children
- Should be able to set
item.selected
correctly. All direct and non-direct parents and children should be affected correctly. - Selecting all children of a parent should mark the parent as selected. All direct and non-direct parents should be affected correctly.
- Deselecting all children of a parent (through API) should mark the parent as deselected. All direct and non-direct parents should be affected correctly.
- Selecting a single child should mark the parent as indeterminate. All direct and non-direct parents should be affected correctly.
- Deselecting a single child should mark the parent as indeterminate. All direct and non-direct parents should be affected correctly.
- Selecting the last non-selected child should mark the parent as selected and NOT indeterminate. All direct and non-direct parents should be affected correctly.
- Deselecting the last selected child should mark the parent as deselected and NOT indeterminate. All direct and non-direct parents should be affected correctly.
- Set nested child, that has its own children, as initially selected. Verify that direct and indirect parents have correct states.
- If a parent is initially selected, all of its children should be selected even if they are initially marked as deselected.
- Partially selected parents should have the default indicator rendered as
indeterminate
- Deleting a single selected child should mark the parent as deselected. All direct and non-direct parents should be affected correctly.
- Deleting a single deselected child should mark the parent as selected. All direct and non-direct parents should be affected correctly.
- Deleting a child should from a selected/deselected parent should not affect its selection state.
- Adding a selected child to deselected parent should mark it as indeterminate. All direct and non-direct parents should be affected correctly.
- Adding a deselected child to selected parent should mark it as indeterminate. All direct and non-direct parents should be affected correctly.
- Adding a (de)selected child to (de)selected parent should not affect the parent selection state.
- Should be able to prevent the
igcSelection
event. - When selecting a range of records using Shift + click key selection of parents should select all their children even if they are not in the selected range.
- Should not be able to interact (select/activate/expand) with disabled item through UI
- Should be able to select/activate/expand disabled item through API
- Should render disabled items as not reachable for tab navigation (
tabIndex
should-1
) - Should not count disabled items as traversable items for keyboard navigation purposes
- If a tree item is expanded and all its children are disabled the focus and activation should not be moved from the item on
Arrow Right
key press - If a tree item is expanded and has enabled children the focus and activation should be moved to the first enabled child on
Arrow Right
key press - Pressing Arrow Up/Down should move the focus and activation to the previous/next enabled and visible item (if there is any) (skipping disabled)
- Pressing Asterisk on a focused item should expand only the enabled and expandable items in the same group
- Should focus and activate the first tree item on
Home
key press - Should focus and activate the last visible tree item on
End
key press - Should not navigate when a tree item has no parent and item is collapsed on
Arrow Left
key press - Should navigate to the parent item of a tree item w/
expanded === true
onArrow Left
key press, moving focus and active - Should collapse expanded tree items on
Arrow Left
key press - Should not navigate when a tree item has no children on
Arrow Right
key press - Should navigate to the first child of an expanded on
Arrow Right
key press, moving focus and active - Should expand collapsed tree item w/ children on
Arrow Right
key press - Should focus and activate the next visible tree item on
Arrow Down
key press - Should only focus the next visible tree item on
Arrow Down + Ctrl
key press - Should focus and activate the previous visible tree item on
Arrow Up
key press - Should only focus the previous visible tree item on
Arrow Up + Ctrl
key press - Should expand all sibling tree items of the focused item on asterisk (
*
) key press - Should active the focused tree item on
Enter
key press - Should not prevent event's default behavior on
Enter
key press - Should only activate the tree item when
tree.selection === 'None'
onSpace
key press - Should select and activate item when
tree.selection !== 'None'
onSpace
key press - Should select item range when
tree.selection !== 'None'
onSpace + Shift
keys press, moving active - Should emit the correct activation, selection and expansion events
- Should render proper role and attributes for the tree
- Should render proper aria attributes for each tree-item
ARIA Support Tree Aria example
An igc-tree
will have role="tree"
. aria-labelledby
should be manually added if there is a label/ heading associated w/ the tree.
An igc-tree-item
's child will be held in a container w/ role="group"
.
An igc-tree-item
will have role="treeitem"
if its hasFocusableContent
property is not enabled.
If it is enabled, the role="treeitem"
will go on the child element.
A item's expanded state will be properly reflected in the item's aria-expanded
attribute.
RTL Support
Assumptions | Limitation Notes |
---|---|