> For the complete documentation index, see [llms.txt](https://docs.avonnicomponents.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.avonnicomponents.com/lwc-components/data-driven-components/tree.md).

# Tree

`avonni-dd-tree`

The Avonni Data Driven Tree displays related records as nested tree items.

## Overview

**Tree** is a data-driven Lightning Web Component that displays related records as nested, expandable tree items, with each level of the hierarchy populated by its own query.

The Tree normally runs in **query mode**. You define a `query` whose `children` describe each nested level and the lookup field that relates it to its parent, plus a per-object `mapping` that maps record fields to tree item properties. The component fetches every level and renders the resulting hierarchy. Alternatively, pass a static `items` array; when `items` is set, `query` and `mapping` are ignored.

### Use Cases

* **Account hierarchies:** Show Accounts with their related Contacts and Opportunities nested beneath.
* **Org and team structures:** Represent reporting or grouping relationships across objects.
* **Record navigation:** Let users drill from a parent record into related children in a single tree.
* **Multi-object browsing:** Combine several SObjects into one nested view (e.g. Account → Contact → Event).
* **Selection pickers:** Use single- or multi-select to choose records from a related hierarchy.

***

## Use Case Examples

### Example 1: Query mode

**Scenario:** Display Accounts with their related Contacts nested beneath each account, showing how many contacts each account has.

```html
<!-- accountTree.html -->
<template>
    <avonni-dd-tree
        query={treeQuery}
        mapping={treeMapping}
        show-item-count
        onselect={handleSelect}
    ></avonni-dd-tree>
</template>
```

```js
// accountTree.js
import { LightningElement } from 'lwc';

export default class AccountTree extends LightningElement {
    treeQuery = {
        objectApiName: 'Account',
        orderBy: 'Name ASC NULLS LAST',
        limit: 50,
        children: [
            {
                objectApiName: 'Contact',
                relationshipField: 'AccountId',
                orderBy: 'Name ASC'
            }
        ]
    };
    treeMapping = {
        Account: {
            label: '{{Record.Name}}',
            name: '{{Record.Id}}',
            metatext: '{{Record.Industry}}'
        },
        Contact: {
            label: '{{Record.Name}}',
            name: '{{Record.Id}}',
            metatext: '{{Record.Title}}'
        }
    };

    handleSelect(event) {
        const { record, selectedNames } = event.detail;
    }
}
```

**Result:** A tree of Accounts, each showing its Industry, with the number of related Contacts after the name, e.g. "Acme (3)". Accounts start collapsed; expanding one loads its Contacts, each showing its Title. Clicking an item fires `select` with the clicked record and the current selection.

<figure><img src="https://2403786217-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FPjQbBtFNxVSSOtnsjuwx%2Fuploads%2F4WMseH0vflmvRTrtTJXp%2Ftree-example-contacts.png?alt=media" alt="A tree of accounts, each with its industry below the name and its number of contacts after it, the first three expanded to show their contacts and titles"><figcaption><p>Example 1 on sample accounts: each account shows its contact count, and the expanded ones list their contacts with their titles.</p></figcaption></figure>

### Example 2: Multi-level, multi-select query

**Scenario:** Build a three-level hierarchy—Account → Contact → Event—and let users select multiple records at once.

```html
<!-- relatedTree.html -->
<template>
    <avonni-dd-tree
        query={treeQuery}
        mapping={treeMapping}
        is-multi-select
        independent-multi-select
        show-item-count
        onselect={handleSelect}
    ></avonni-dd-tree>
</template>
```

```js
// relatedTree.js
import { LightningElement } from 'lwc';

export default class RelatedTree extends LightningElement {
    treeQuery = {
        objectApiName: 'Account',
        orderBy: 'Name ASC',
        limit: 25,
        children: [
            {
                objectApiName: 'Contact',
                relationshipField: 'AccountId',
                orderBy: 'Name ASC',
                children: [
                    {
                        objectApiName: 'Event',
                        relationshipField: 'WhoId',
                        orderBy: 'Subject ASC NULLS LAST'
                    }
                ]
            }
        ]
    };
    treeMapping = {
        Account: { label: '{{Record.Name}}', name: '{{Record.Id}}' },
        Contact: {
            label: '{{Record.Name}}',
            name: '{{Record.Id}}',
            metatext: '{{Record.Title}}'
        },
        Event: { label: '{{Record.Subject}}', name: '{{Record.Id}}' }
    };

    handleSelect(event) {
        const { record, selectedNames } = event.detail;
        // selectedNames holds every checked item among the loaded (expanded) levels
    }
}
```

**Result:** A three-level tree where each Account expands into Contacts, and each Contact expands into its related Events. Checkboxes let users select records; because `independent-multi-select` is set, selecting a parent does not auto-select its children. Each `select` event reports the full set of checked item names.

<figure><img src="https://2403786217-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FPjQbBtFNxVSSOtnsjuwx%2Fuploads%2F7PaFmbH1vEbKWGWGIyjF%2Ftree-example-multi-select.png?alt=media" alt="A tree of accounts with a checkbox on every item, the first three expanded to their contacts and one contact expanded to its events"><figcaption><p>Example 2 on sample accounts: checkboxes on every level, accounts expanded to their contacts, and one contact expanded to its events.</p></figcaption></figure>

***

## Specifications

### Attributes

| Name                       | Description                                                                                                                                                                                                                                                                                                                                                                                                              | Type                            | Default | Required |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------- | ------- | -------- |
| `independent-multi-select` | Used only if `is-multi-select` is present. If present, the parent and children nodes will be selected independently of each other.                                                                                                                                                                                                                                                                                       | Boolean                         | `false` |          |
| `is-multi-select`          | If present, multiple items can be selected and a checkbox is displayed to the left of the items.                                                                                                                                                                                                                                                                                                                         | Boolean                         | `false` |          |
| `items`                    | Array of static items displayed in the tree. When this property is set, the tree ignores the `query` and `mapping` properties and displays the items directly.                                                                                                                                                                                                                                                           | DdTreeItem\[]                   | —       |          |
| `mapping`                  | Object defining the way the records returned by the query should be displayed in the tree. Each key is an SObject API name (e.g., 'Account', 'Contact'), and each value is an object that defines how the records fields should be mapped to the tree item properties. To insert the value of a field, use the syntax `{{Record.FieldApiName}}`. For example, to use the value of the Name field, use `{{Record.Name}}`. | object.\<string, DdTreeMapping> | —       |          |
| `query`                    | Object describing the queries that should be executed to fetch the records on each level of the relationship graph.                                                                                                                                                                                                                                                                                                      | DdNestedQueryElementQuery       | —       |          |
| `refresh-emp`              | Object describing a platform event that should be subscribed to in order to refresh the component when an event is published.                                                                                                                                                                                                                                                                                            | DdElementRefreshEmp             | —       |          |
| `show-item-count`          | If present, the number of children items is displayed next to each item label.                                                                                                                                                                                                                                                                                                                                           | Boolean                         | `false` |          |

### Methods

| Name      | Description                                                   | Argument Name | Argument Type | Argument Description |
| --------- | ------------------------------------------------------------- | ------------- | ------------- | -------------------- |
| `refresh` | Refresh the query and the records displayed in the component. |               |               |                      |

### Mapping

The Tree's `mapping` is keyed by SObject API name. Each entry maps that object's record fields to tree item properties using the `{{Record.FieldApiName}}` syntax.

| Mapping key | Maps to                                                                                                                                                                               |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `label`     | Item label (the text shown for the node).                                                                                                                                             |
| `name`      | Unique item identifier. Must resolve to the record Id (`{{Record.Id}}`, the default when omitted): any other field stops children from loading and leaves `record` empty in `select`. |
| `metatext`  | Secondary text displayed below the item label.                                                                                                                                        |
| `disabled`  | If true, the item is disabled and cannot be selected or toggled.                                                                                                                      |

```js
const TREE_MAPPING = {
    Account: {
        label: '{{Record.Name}}',
        name: '{{Record.Id}}',
        metatext: '{{Record.Industry}}'
    },
    Contact: {
        label: '{{Record.Name}}',
        name: '{{Record.Id}}',
        metatext: '{{Record.Title}}'
    }
};
```

Within `query`, each `children` entry must specify a `relationshipField`—the lookup field on the child SObject that points back to the parent level (for example, `AccountId` on Contact relating it to Account).

### Custom Events

#### `select`

Event fired when an item is selected or unselected.

The `select` event returns the following parameters.

| Parameter       | Type      | Description                                                                                                     |
| --------------- | --------- | --------------------------------------------------------------------------------------------------------------- |
| `item`          | object    | Tree item that was selected or unselected.                                                                      |
| `record`        | object    | Record of the item that was selected or unselected. In static mode, no record is associated and this is `null`. |
| `selectedNames` | string\[] | Array of selected item names.                                                                                   |

The event properties are as follows.

| Property   | Value | Description                                                                                               |
| ---------- | ----- | --------------------------------------------------------------------------------------------------------- |
| bubbles    | false | This event does not bubble.                                                                               |
| cancelable | false | This event has no default behavior that can be canceled. You can't call `preventDefault()` on this event. |
| composed   | false | This event does not propagate outside of the component in which it was dispatched.                        |

### Styling Hooks

| CSS Variable                                     | Type      | Default    |
| ------------------------------------------------ | --------- | ---------- |
| `--avonni-dd-tree-header-font-size`              | dimension | `0.875rem` |
| `--avonni-dd-tree-header-font-style`             | string    | `normal`   |
| `--avonni-dd-tree-header-font-weight`            | number    | `700`      |
| `--avonni-dd-tree-header-text-color`             | color     | —          |
| `--avonni-dd-tree-header-title-image-height`     | dimension | `3rem`     |
| `--avonni-dd-tree-header-title-image-object-fit` | string    | `cover`    |
| `--avonni-dd-tree-header-title-image-width`      | string    | `unset`    |

## Key Considerations

* **Query mode or static items:** In query mode you must supply a `query` and a `mapping` to render anything. Alternatively, pass a static `items` array; when `items` is set, `query` and `mapping` are ignored.
* **Mapping is keyed by object:** Every SObject appearing in the query (parent and each child) needs its own entry in `mapping`, keyed by API name.
* **`relationshipField` is required for children:** Each child query must name the lookup field that ties it to the parent level, or that level won't load.
* **Selection mode matters:** By default selection is single; add `is-multi-select` for checkboxes, and `independent-multi-select` to decouple parent/child selection.
* **Mind the limits:** `limit` applies to the root query only; each child level loads up to 100 records per parent (fewer if the root `limit` is lower), with a Show more button. `filter` (a SOQL WHERE expression) applies to the root query only; filters on child levels are ignored.
* **Nodes load on expand:** Nodes start collapsed and each expand runs a query.
* **Best Practice:** Map `name` to `{{Record.Id}}` on every object so each tree item has a unique, stable identifier, and set `orderBy` on each query level (and a sensible `limit` on the root query) to keep large hierarchies readable.

***

## Troubleshooting Common Issues

* **Children don't appear:** Verify each child query has the correct `relationshipField` (the lookup on the child object pointing to the parent), that `name` is mapped to `{{Record.Id}}` (or omitted) on every level, and that the running user can access those records.
* **Items render blank or without labels:** Ensure every queried object has a `mapping` entry with `label` and a unique `name` (such as `{{Record.Id}}`).
* **Selection behaves unexpectedly:** Confirm `is-multi-select` is present for checkbox selection, and add `independent-multi-select` if parent and child selection should not cascade.
* **If issues persist:** Contact our support team at <support@avonni.app> for assistance.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.avonnicomponents.com/lwc-components/data-driven-components/tree.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
