# AssetTree

*Category:* Components
*Section:* Selection
*Source:* https://uikit.developers.rio.cloud/#/components/assetTree
*Captured:* 2026-04-27T14:57:37.479Z

## AssetTree

The asset tree components are using labels that need to be defined from the outside of the components, meaning the come from your service. To align on the labels and their translations you should use the shared project on Phrase.

### Example: Example 1

Filter

5241
4

Group - Abbie D'Amore - 4617 14

Group - Abdullah Gorczany - 4604 12

Group - Ada Bergnaum - 6885 15

Group - Adam Spencer - 1326 6

Group - Adrain Rice - 3568 7

Group - Agustin Sawayn - 9288 13

Group - Agustina Mitchell - 7938 12

Group - Alba Dickens - 4029 15

Group - Albert Larkin Jr. - 4366 12

Group - Albert Turcotte - 3213 17

Group - Albertha Maggio Jr. - 5254 14

Group - Alejandro Dach Jr. - 7483 17

Group - Alek Goldner - 1787 12

Group - Alek Hettinger V - 4864 13

Group - Alessandra Effertz - 8203 14

200

200

Load trucks Clear tree Toggle all groups selection

Current category:
trucks
Selected groups:

Selected assets:

Expanded groups:
Trailer Group

Selected drivers:

Search value:

Asset type filter:
[]

#### React (tsx)

```tsx
import { useState } from 'react';
import { get, isEmpty, isObject, random } from 'es-toolkit/compat';
import { faker } from '@faker-js/faker';

import AssetTree from '@rio-cloud/rio-uikit/AssetTree';
import TreeCategory from '@rio-cloud/rio-uikit/TreeCategory';
import Tree, {
    type TreeItemName,
    type TreeGroup,
    type TreeItem,
    type SelectionChangeResponse,
} from '@rio-cloud/rio-uikit/Tree';
import TreeSearch from '@rio-cloud/rio-uikit/TreeSearch';
import TreeSummary from '@rio-cloud/rio-uikit/TreeSummary';
import TreeOption from '@rio-cloud/rio-uikit/TreeOption';
import Button from '@rio-cloud/rio-uikit/Button';

const CATEGORY_FILTER = 'filter';
const CATEGORY_TRUCKS = 'trucks';
const CATEGORY_DRIVER = 'driver';
const CATEGORY_LOREM = 'lorem';

const randomDrivers = Array.from({ length: 200 }, (_, index) => ({
    id: `74e8eb86-18a1-4abe-90cb-aeee7909f85${index}`,
    name: {
        firstName: faker.internet.username(),
        lastName: faker.person.firstName(),
    },
    type: 'driver',
}));

const getTruckGroups = (): TreeGroup[] => {
    const groups = Array.from({ length: random(400, 600) }, (_, index) => ({
        id: `group-${index}`,
        name: `Group - ${faker.person.fullName()} - ${random(1000, 9999)}`,
    }));
    return [
        ...groups,
        {
            id: 'truck-6ba7c2ec-8bd4-4470-98a4-313c9d33e8d5',
            name: 'Truck Group North',
        },
        {
            id: 'truck-b40aabcf-01f8-4be2-bc3d-9157cbdb395f',
            name: 'Truck Group East',
        },
        {
            id: 'truck-722a5f86-eb6c-46cf-83da-3f8dbfbcca5e',
            name: 'Truck Group South',
        },
        {
            id: 'truck-0250a8aa-721e-40b4-b1ea-7908acddfdf4',
            name: 'Truck Group West',
            className: 'foobar',
        },
        {
            id: 'unassigned',
            name: 'Ungrouped',
            position: 'last',
        },
    ];
};

const trailerGroups: TreeGroup[] = [
    {
        id: '6ba7c2ec-8bd4-4470-98a4-313c9d33e8d5',
        name: 'Trailer Group',
    },
];

const trailer: TreeItem[] = [
    {
        id: '110191ac-d06d-4567-b13a-7b7fd85d9731',
        name: 'Trailer 03',
        type: 'trailer',
        groupIds: ['unassigned'],
    },
    {
        id: '110191ac-d06d-4567-b13a-7b7fd85d9740',
        name: 'Trailer 04',
        type: 'trailer',
        groupIds: ['unassigned'],
    },
    {
        id: '16807251-95d2-4d73-afd0-4fbd0eadebf4',
        name: 'Trailer 01',
        type: 'trailer',
        groupIds: ['6ba7c2ec-8bd4-4470-98a4-313c9d33e8d5'],
    },
    {
        id: '16807251-95d2-4d73-afd0-4fbd0eadebf6',
        name: 'Trailer 02',
        type: 'trailer',
        groupIds: ['6ba7c2ec-8bd4-4470-98a4-313c9d33e8d5'],
    },
];

const getTrucks = (namePrefix = 'Vehicle-'): TreeItem[] => {
    const groups = getTruckGroups();
    const randomTrucks = Array.from({ length: random(5000, 6000) }, (_, index) => ({
        id: `010191ac-d06d-4567-b13a-7b7fd85d97${index}`,
        name: `${namePrefix}${random(1000, 9999)}`,
        info: `M-AN 1${String(index).padStart(3, '0')}`,
        type: 'truck',
        groupIds: [faker.helpers.arrayElement(groups).id],
    }));
    return [...randomTrucks, ...trailer];
};

const truckGroupsWithEmptyGroup: TreeGroup[] = [
    ...getTruckGroups(),
    {
        id: '0350a8aa-721e-40b4-b1ea-7908acddfdf4',
        name: 'My Empty Group',
        disabled: true,
    },
    {
        id: 'truck-0250a8aa-721e-40b4-b1ea-7908acddfdf1',
        name: 'Truck Group West 2',
    },
    {
        id: 'truck-0250a8aa-721e-40b4-b1ea-7908acddfdf2',
        name: 'Truck Group West 3',
    },
    ...trailerGroups,
];

const defaultExpandedTruckGroups: string[] = ['6ba7c2ec-8bd4-4470-98a4-313c9d33e8d5'];

const AssetTreeExample = () => {
    const [trucks, setTrucks] = useState<TreeItem[]>(getTrucks());
    const [truckGroups, setTruckGroups] = useState<TreeGroup[]>(truckGroupsWithEmptyGroup);
    const [selectedTruckGroupIds, setSelectedTruckGroupIds] = useState<string[]>([]);
    const [selectedTruckIds, setSelectedTruckIds] = useState<string[]>([]);
    const [selectedDrivers, setSelectedDrivers] = useState<string[]>([]);
    const [expandedTruckGroups, setExpandedTruckGroups] = useState(defaultExpandedTruckGroups);
    const [currentCategoryId, setCurrentCategoryId] = useState(CATEGORY_TRUCKS);
    const [isTreeOpen, setIsTreeOpen] = useState(true);
    const [searchValue, setSearchValue] = useState('');
    const [showEmptyGroups, setShowEmptyGroups] = useState(false);
    const [showAssetGroups, setShowAssetGroups] = useState(true);
    const [currentTypeFilter, setCurrentTypeFilter] = useState<string[]>([]);

    const handleSelectTruck = ({ items, groups }: SelectionChangeResponse) => {
        setSelectedTruckIds(items);
        setSelectedTruckGroupIds(groups);
    };

    const handleExpandTruckGroups = (newExpandedTruckGroups: string[]) =>
        setExpandedTruckGroups(newExpandedTruckGroups);

    const handleSelectDriver = ({ items }: SelectionChangeResponse) => setSelectedDrivers(items);
    const handleChangeCategories = (categoryId: string) => setCurrentCategoryId(categoryId);
    const handleUpdateSearch = (value: string) => setSearchValue(value);
    const handleToggleTree = (toggle: boolean) => setIsTreeOpen(toggle);
    const handleToggleEmptyGroups = () => setShowEmptyGroups(!showEmptyGroups);
    const handleToggleAssetGroups = () => setShowAssetGroups(!showAssetGroups);

    const renderSelectedItemsOfList = (selectedItemIds: string[], list: TreeGroup[] | TreeItem[]) =>
        selectedItemIds.map(selectedItemId => {
            const result = list.find(listItem => listItem.id === selectedItemId);
            if (result) {
                const name = isObject(result.name)
                    ? `${(result.name as TreeItemName).firstName} ${(result.name as TreeItemName).lastName}`
                    : result.name;
                return <li key={selectedItemId}>{name}</li>;
            }
            return null;
        });

    // Custom filter function for driver as for this we showcase the usage of a custom search component
    const filteredDrivers = randomDrivers.filter(driver =>
        `${get(driver, 'name.firstName', '')} ${get(driver, 'name.lastName', '')}`.includes(searchValue)
    );

    return (
        <div className='display-flex flex-wrap gap-25'>
            <div>
                <AssetTree
                    bordered
                    minWidth={300}
                    maxWidth={450}
                    currentCategoryId={currentCategoryId}
                    onCategoryChange={handleChangeCategories}
                    height={500}
                    isOpen={isTreeOpen}
                    onToggleTree={handleToggleTree}
                    useOffscreen
                >
                    <TreeCategory key={CATEGORY_FILTER} id={CATEGORY_FILTER} label='Filter' icon='rioglyph-filter'>
                        <div className='margin-15'>Filter</div>
                    </TreeCategory>

                    <TreeCategory
                        key={CATEGORY_TRUCKS}
                        id={CATEGORY_TRUCKS}
                        label='Assets'
                        icon='rioglyph-truck'
                        hasSelection={!isEmpty(selectedTruckIds) || !isEmpty(selectedTruckGroupIds)}
                    >
                        <Tree
                            groups={showAssetGroups ? truckGroups : []}
                            items={trucks}
                            expandedGroups={expandedTruckGroups}
                            onExpandGroupsChange={handleExpandTruckGroups}
                            selectedGroups={selectedTruckGroupIds}
                            selectedItems={selectedTruckIds}
                            onSelectionChange={handleSelectTruck}
                            searchPlaceholder='Find asset'
                            onSearchChange={handleUpdateSearch}
                            showEmptyGroups={showEmptyGroups}
                            onTypeFilterChange={setCurrentTypeFilter}
                            treeOptionsTooltip='Vehicle tree options'
                            treeOptions={[
                                <TreeOption
                                    key='emptyGroupsToggle'
                                    label='Show empty groups'
                                    isChecked={showEmptyGroups}
                                    onChange={handleToggleEmptyGroups}
                                />,
                                <TreeOption
                                    key='assetGroupsToggle'
                                    label='Show groups'
                                    isChecked={showAssetGroups}
                                    onChange={handleToggleAssetGroups}
                                />,
                            ]}
                        />
                    </TreeCategory>

                    <TreeCategory
                        key={CATEGORY_DRIVER}
                        id={CATEGORY_DRIVER}
                        label='My Drivers'
                        icon='rioglyph-driver'
                        hasSelection={!isEmpty(selectedDrivers)}
                    >
                        <Tree
                            items={filteredDrivers}
                            selectedItems={selectedDrivers}
                            onSelectionChange={handleSelectDriver}
                            hasMultiselect={!isEmpty(filteredDrivers)}
                            summary={<TreeSummary assetCounts={{ driver: filteredDrivers.length }} />}
                            search={
                                <TreeSearch
                                    value={searchValue}
                                    placeholder='this is a custom search'
                                    onChange={handleUpdateSearch}
                                />
                            }
                        />
                    </TreeCategory>

                    <TreeCategory key='lorem-ipsum' id={CATEGORY_LOREM} label='Lorem ipsum' icon='rioglyph-layer-pois'>
                        <div className='custom-pois-wrapper height-100pct'>
                            <Tree
                                items={filteredDrivers}
                                selectedItems={selectedDrivers}
                                onSelectionChange={handleSelectDriver}
                                hasMultiselect={!isEmpty(filteredDrivers)}
                                treeHeaderContent={
                                    <ul className='rounded-none nav nav-pills nav-pills-filled nav-justified text-size-18'>
                                        <li className='active'>
                                            <span className='rioglyph rioglyph-pushpin' />
                                        </li>
                                        <li>
                                            <span className='rioglyph rioglyph-geofence' />
                                        </li>
                                        <li>
                                            <span className='rioglyph rioglyph-workshop' />
                                        </li>
                                        <li>
                                            <span className='rioglyph rioglyph-filling-e-station' />
                                        </li>
                                    </ul>
                                }
                                summary={<TreeSummary assetCounts={{ driver: filteredDrivers.length }} />}
                                search={
                                    <TreeSearch
                                        value={searchValue}
                                        placeholder='this is a custom search'
                                        onChange={handleUpdateSearch}
                                    />
                                }
                            />
                        </div>
                    </TreeCategory>
                </AssetTree>
                <div className='btn-toolbar margin-top-25'>
                    <Button
                        onClick={() => {
                            setTrucks(getTrucks('RIO'));
                            setTruckGroups(getTruckGroups());
                        }}
                    >
                        Load trucks
                    </Button>
                    <Button
                        onClick={() => {
                            setTrucks([]);
                            setTruckGroups([]);
                        }}
                    >
                        Clear tree
                    </Button>
                    <Button
                        onClick={() => {
                            const isListEmpty = isEmpty(selectedTruckGroupIds);
                            setSelectedTruckGroupIds(isListEmpty ? truckGroups.map(group => group.id) : []);
                        }}
                    >
                        Toggle all groups selection
                    </Button>
                </div>
            </div>
            <div>
                <div className='h6'>Current category:</div>
                <ul>{currentCategoryId}</ul>
                <div className='h6'>Selected groups:</div>
                <ul>{renderSelectedItemsOfList(selectedTruckGroupIds, truckGroups)}</ul>
                <div className='h6'>Selected assets:</div>
                <ul>{renderSelectedItemsOfList(selectedTruckIds, trucks)}</ul>
                <div className='h6'>Expanded groups:</div>
                <ul>{renderSelectedItemsOfList(expandedTruckGroups, truckGroups)}</ul>
                <hr />
                <div className='h6'>Selected drivers:</div>
                <ul>{renderSelectedItemsOfList(selectedDrivers, randomDrivers)}</ul>
                <hr />
                <div className='h6'>Search value:</div>
                <ul>{searchValue}</ul>
                <hr />
                <div className='h6'>Asset type filter:</div>
                <ul>{`[${currentTypeFilter.join(', ')}]`}</ul>
            </div>
        </div>
    );
};

export default AssetTreeExample;
```

#### Props: AssetTree

### AssetTree

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| fly | boolean | false | Defines if the component will overlap the body content. |
| resizable | boolean | true | Defines whether or not the sidebar is resizable. |
| bordered | boolean | false | Defines whether the component has a border or not. |
| width | number | 350 | Defines the width of the component. The value is set as inline style. Note: when component is resizable it will take the provided width in px only and convert it to number in case. |
| minWidth | number | 100 | Defines the minimum width of the component in px that will take effect when resizing. |
| maxWidth | number | 0 | Defines the maximum width of the component in px that will take effect when resizing. |
| height | number | — | Defines the height of the component in px. |
| isOpen | boolean | true | Defines whether the component is open or not. |
| onToggleTree | (isOpen: boolean) => void | () => {} | Callback for when the tree visibility is toggled. |
| currentCategoryId | string | — | The id of the category which is currently active and shall be shown. |
| onCategoryChange | (selectedCategoryId: string) => void | () => {} | Callback for handling change of category. |
| onResizeEnd | VoidFunction | () => {} | Callback for when the resize is done. |
| useOffscreen | boolean | false | Defines whether the tree components are rendered offscreen and kept mounted in the DOM. |
| className | string | — | Additional classes added on the wrapper element. |

#### Props: TreeCategory

### TreeCategory

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| id | string | — | A unique identifier for that category. |
| icon | string | — | The rioglyph icon name for that category. |
| label | string \| React.ReactNode | — | The optional label for the category which will be shown in a tooltip. |
| hasSelection | boolean | — | Defines whether or not a selection indicator should be shown. |

#### Props: Tree

### Tree

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| groups | TreeGroup[] | [] | The list of groups of the items. If no groups are provided all items are rendered as flat list. |
| └id | string | — | A unique identifier of a group. |
| └name | string \| React.ReactNode | — | The name of a group. |
| └position | 'last' | — | Can be set to "last" to enforce the last position in the tree. |
| └disabled | boolean | — | Disallows the selection of the group itself. |
| └icon | string | — | The rioglyph icon name for a group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └expandedIcon | string | — | The rioglyph icon name for a expanded group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └className | string | — | Additional classes added to the group element. |
| items | TreeItem[] | [] | The list of items. |
| └id | string | — | A unique identifier of an item. |
| └name | string \| TreeItemName | — | The name of an item. Either it is a plain string or an object composed of: firstName and lastName where lastName is mandatory. |
| └info | string \| React.ReactNode | — | The subline of an item. This can e used to show additional information for that item. |
| └type | string | — | The primary type of the item. This is also used as the fallback icon name and refers to the name of the respective rioglyph icon (excluding the rioglyph- prefix). |
| └icon | string \| null | — | Optional icon override for the item. If set to a string (e.g. 'truck'), this icon will be used explicitly. If set to undefined, the type property will be used as the fallback icon. If set to null, no icon will be rendered, even if type is defined. This allows full control over the icon behavior while maintaining backward compatibility with type-based icons. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └subType | string | — | Optional sub-type of the item. This refers to the name of an additional rioglyph icon (excluding the rioglyph- prefix), typically used to render a secondary icon next to the primary one (Note: for fuel types better use the pairIcon prop). |
| └pairIcon | string \| null \| undefined | — | Optional pair icon override for the subType. If set to a string (e.g. 'fuel-gas'), this icon will be used explicitly. If set to undefined, the subType property will be used as the fallback icon. If set to null, no icon will be rendered, even if subType is defined. This allows full control over the icon behavior while maintaining backward compatibility with subType-based icons. |
| └groupIds | string[] | [] | List of group ids the items is associated with. |
| └className | string | — | Additional classes added to the item element. |
| selectedGroups | string[] | [] | List of selected group ids. |
| selectedItems | string[] | [] | List of selected item ids. |
| onSelectionChange | ({ items, groups }: SelectionChangeResponse) => void | — | Merged Callback for item and group selection changes. It responds with a selection object that contains the selected itemIds and groupIds: { items: [], groups: [] } |
| hasMultiselect | boolean | true | Defines the selection behavior of the tree. |
| showRadioButtons | boolean | false | Defines if the single selection should also show radios. |
| hideSearch | boolean | false | Defines whether or not the built-in Search is shown. |
| searchPlaceholder | string | — | The text used as placeholder for the search input. |
| onSearchChange | (value: string) => void | — | Callback for when the search value changes. |
| search | React.ReactNode | — | Used to define custom search component which replaces the built-in search. |
| summary | React.ReactNode | — | Used to define custom asset type counter component which replaces the built-in summary. |
| hideSummary | boolean | false | Defines whether a summary is shown. |
| onTypeFilterChange | (currentTypes: string[]) => void | — | Callback triggered when the built-in asset type filter changes. This is only available when the default summary is used. |
| hideTreeHead | boolean | false | Defines whether the entire area below the search field is shown or not. Note: Disabling the tree head will hide the select all checkbox and the tree options as well as the tree summary. |
| treeHeaderContent | React.ReactElement | — | Additional custom content that is rendered at the top of the tree component. This can be used for nav pills. |
| scrollHeight | number | — | Defines the max-height of the scrollable list. |
| expandedGroups | string[] | — | List of group ids which are expanded. |
| onExpandGroupsChange | (newExpandedGroups: string[]) => void | — | Callback function triggered when a group expands or collapses. |
| showEmptyGroups | boolean | true | Defines whether empty groups are shown or not. |
| treeOptions | React.ReactNode[] | — | Component to offer customization options for the tree. |
| treeOptionsTooltip | React.ReactNode | — | Tooltip content for the tree options dropdown. |
| disableAnimation | boolean | false | Disables animation when filtering or using search |
| virtualizeThreshold | number | 50 | The number of items (including groups and children) used for virtualizing the tree. |
| overscan | number | 5 | The number of items rendered beyond the visible area of a virtualized tree. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSearch

### TreeSearch

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| value | string | — | The search value to be shown and used for the search. |
| onChange | (newValue: string, event: React.ChangeEvent \| React.MouseEvent) => void | () => {} | Callback for when the search value changes. |
| placeholder | string | — | The placeholder text used for the input field. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSummary

### TreeSummary

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| assetCounts | TreeSummaryCounts | — | The object containing various asset type counter. |
| └truck | number | — | The amount of trucks |
| └trailer | number | — | The amount of trailers |
| └bus | number | — | The amount of buses |
| └van | number | — | The amount of vans |
| └car | number | — | The amount of cars |
| └driver | number | — | The amount of drivers |
| gridCols | number | 4 | The number of grid columns used for the built-in TreeSummaryRow. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSummaryRow

### TreeSummaryRow

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| gridCols | number | 4 | Defined the number of grid columns for a single row. Note, when the amount of children exceed the columns it will wrap around to a new line. |

#### Props: TypeCounter

### TypeCounter

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| type | string | — | The item type for that counter. This will be used as a return value for the onClick callback. |
| icon | string | — | The icon name. Note, when using the built-in generic type counter, the icon name will the same as the item type. So make sure there is a corresponding icon for the defined type. |
| isActive | boolean | — | Sets the active styling if active |
| hasFilter | boolean | false | Should be set when there is a type filter set in the tree to style the counter accordingly. |
| enableActivity | boolean | false | Allows for interactivity. Use this prop when you allow clicking on the counter. |
| hideOnZero | boolean | false | Defines if the counter is rendered at all when the value is not defined ot 0. |
| onClick | (type: string) => void | — | Callback function when the counter is clicked. It returns the type value. Make sure the "type" prop is defined to receive the value in the callback. |
| value | string \| React.ReactNode \| number | — | A custom value to be shown in the counter. |

#### Props: TreeOption

### TreeOption

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| isChecked | boolean | false | Defines whether the option is set. |
| onChange | (event: React.MouseEvent<HTMLDivElement>) => void | — | Callback triggered when option is selected. |
| label | string \| React.ReactNode | — | The label for the option. |
| className | string | — | Additional classes added to the wrapping element. |

## AssetTree with single select

### Example: Example 2

9
10
5
6

My Empty Group 3

Truck Group East 5

Truck Group North 4
N18-G259 / M-AN 1006
N18-G545 / M-AN 1029
N18-G632 / M-AN 1011
N18-G845 / M-AN 1003

Truck Group South 7

Truck Group West 6

All my unassigned Trucks 5

Current category:
assets
Selected tree groups:

Selected assets:

Expanded tree groups:
Truck Group North

#### React (tsx)

```tsx
import { useState } from 'react';
import { isEmpty, isObject, random } from 'es-toolkit/compat';
import { faker } from '@faker-js/faker';

import AssetTree from '@rio-cloud/rio-uikit/AssetTree';
import TreeCategory from '@rio-cloud/rio-uikit/TreeCategory';
import Tree, {
    type TreeGroup,
    type TreeItem,
    type TreeItemName,
    type SelectionChangeResponse,
} from '@rio-cloud/rio-uikit/Tree';

const CATEGORY_ASSETS = 'assets';

const assetGroups: TreeGroup[] = [
    {
        id: '6ba7c2ec-8bd4-4470-98a4-313c9d33e8d5',
        name: 'Truck Group North',
    },
    {
        id: 'b40aabcf-01f8-4be2-bc3d-9157cbdb395f',
        name: 'Truck Group East',
    },
    {
        id: '722a5f86-eb6c-46cf-83da-3f8dbfbcca5e',
        name: 'Truck Group South',
    },
    {
        id: '0250a8aa-721e-40b4-b1ea-7908acddfdf4',
        name: 'Truck Group West',
    },
    {
        id: '0350a8aa-721e-40b4-b1ea-7908acddfdf4',
        name: 'My Empty Group',
    },
    {
        id: 'static/unassignedTrucks',
        name: 'All my unassigned Trucks',
        position: 'last',
    },
];

const defaultExpandedAssetGroups = ['6ba7c2ec-8bd4-4470-98a4-313c9d33e8d5'];
const assetTypes = ['truck', 'bus', 'van', 'trailer'];

const assets = Array.from({ length: 30 }, (_, index) => ({
    id: `010191ac-d06d-4567-b13a-7b7fd85d97${index}`,
    name: `N18-G${random(100, 999)} / M-AN 1${String(index).padStart(3, '0')}`,
    type: faker.helpers.arrayElement(assetTypes),
    groupIds: [faker.helpers.arrayElement(assetGroups).id],
}));

const AssetTreeSingleSelectExample = () => {
    const [selectedAssetGroupIds, setSelectedAssetGroupIds] = useState<string[]>([]);
    const [selectedAssetIds, setSelectedAssetIds] = useState<string[]>([]);
    const [expandedAssetGroups, setExpandedAssetGroups] = useState<string[]>(defaultExpandedAssetGroups);
    const [currentCategoryId, setCurrentCategoryId] = useState<string>(CATEGORY_ASSETS);
    const [isTreeOpen, setIsTreeOpen] = useState(true);

    const handleSelectAsset = ({ items, groups }: SelectionChangeResponse) => {
        setSelectedAssetIds(items);
        setSelectedAssetGroupIds(groups);
    };

    const handleExpandAssetGroups = (expandedGroups: string[]) => setExpandedAssetGroups(expandedGroups);
    const handleChangeCategories = (newCategoryId: string) => setCurrentCategoryId(newCategoryId);
    const handleToggleTree = (toggle: boolean) => setIsTreeOpen(toggle);

    const renderSelectedItemsOfList = (selectedItemIds: string[], list: TreeGroup[] | TreeItem[]) =>
        selectedItemIds.map(selectedItemId => {
            const result = list.find(listItem => listItem.id === selectedItemId);
            if (result) {
                const name = isObject(result.name)
                    ? `${(result.name as TreeItemName).firstName} ${(result.name as TreeItemName).lastName}`
                    : result.name;
                return <li key={selectedItemId}>{name}</li>;
            }
            return null;
        });

    return (
        <div className='display-flex flex-wrap gap-25 overflow-auto'>
            <div>
                <AssetTree
                    resizable
                    bordered
                    minWidth={300}
                    maxWidth={450}
                    currentCategoryId={currentCategoryId}
                    onCategoryChange={handleChangeCategories}
                    height={500}
                    isOpen={isTreeOpen}
                    onToggleTree={handleToggleTree}
                >
                    <TreeCategory
                        key={CATEGORY_ASSETS}
                        id={CATEGORY_ASSETS}
                        label='Assets'
                        icon='rioglyph-truck'
                        hasSelection={!isEmpty(selectedAssetIds) || !isEmpty(selectedAssetGroupIds)}
                    >
                        <Tree
                            groups={assetGroups}
                            items={assets}
                            expandedGroups={expandedAssetGroups}
                            onExpandGroupsChange={handleExpandAssetGroups}
                            selectedGroups={selectedAssetGroupIds}
                            selectedItems={selectedAssetIds}
                            onSelectionChange={handleSelectAsset}
                            searchPlaceholder='Find asset by name'
                            hasMultiselect={false}
                        />
                    </TreeCategory>
                </AssetTree>
            </div>
            <div>
                <div className='h6'>Current category:</div>
                <ul>{currentCategoryId}</ul>
                <div className='h6'>Selected tree groups:</div>
                <ul>{renderSelectedItemsOfList(selectedAssetGroupIds, assetGroups)}</ul>
                <div className='h6'>Selected assets:</div>
                <ul>{renderSelectedItemsOfList(selectedAssetIds, assets)}</ul>
                <div className='h6'>Expanded tree groups:</div>
                <ul>{renderSelectedItemsOfList(expandedAssetGroups, assetGroups)}</ul>
            </div>
        </div>
    );
};

export default AssetTreeSingleSelectExample;
```

#### HTML (html)

```html
<div class="display-flex flex-wrap gap-25 overflow-auto">
    <div>
        <div class="AssetTree border fluid" style="width: 350px; height: 500px;">
            <div class="AssetTreeResizeLimit" style="left: 450px;">
            </div>
            <div class="AssetTreeContent">
                <div class="TreeSidebar">
                    <ul class="TreeSidebarNavigation">
                        <li class="active">
                            <div class="selection-bubble">
                                <span class="rioglyph rioglyph-truck">
                                </span>
                            </div>
                        </li>
                    </ul>
                    <div class="TreeSidebarToggle">
                        <span class="rioglyph rioglyph-chevron-left">
                        </span>
                    </div>
                </div>
                <div class="AssetTreeBody scrollbar-fly-in smooth-scrollbar-wrapper" style="position: relative; overflow: hidden; width: 100%; height: 100%;">
                    <div class="scrollbar-view" style="position: absolute; inset: 0px; overflow: scroll; margin-right: 0px; margin-bottom: 0px;">
                        <div class="scrollbar-content-wrapper">
                            <div class="Tree">
                                <div class="TreeHeader">
                                    <div class="TreeSearch">
                                        <div class="input-group flex-1-0">
                                            <span class="input-group-addon">
                                                <span class="rioglyph rioglyph-search" aria-hidden="true">
                                                </span>
                                            </span>
                                            <div class="ClearableInput input-group">
                                                <input placeholder="Find asset by name" class="form-control" type="text" tabindex="0" value="">
                                                <span class="clearButton hide">
                                                    <span class="clearButtonIcon rioglyph rioglyph-remove-sign">
                                                    </span>
                                                </span>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="TreeHead display-flex gap-5 padding-15">
                                        <div class="border border-right-only hidden-empty padding-right-10 margin-right-2">
                                        </div>
                                        <div class="display-flex justify-content-between align-items-start width-100pct">
                                            <div class="TreeSummary display-flex flex-wrap align-items-center gap-10 padding-left-3">
                                                <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                    <span class="rioglyph rioglyph-truck text-size-16 margin-right-2">
                                                    </span>
                                                    <span class="TreeLabelCount label label-condensed label-muted label-filled">9</span>
                                                </div>
                                                <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                    <span class="rioglyph rioglyph-bus text-size-16 margin-right-2">
                                                    </span>
                                                    <span class="TreeLabelCount label label-condensed label-muted label-filled">10</span>
                                                </div>
                                                <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                    <span class="rioglyph rioglyph-van text-size-16 margin-right-2">
                                                    </span>
                                                    <span class="TreeLabelCount label label-condensed label-muted label-filled">5</span>
                                                </div>
                                                <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                    <span class="rioglyph rioglyph-trailer text-size-16 margin-right-2">
                                                    </span>
                                                    <span class="TreeLabelCount label label-condensed label-muted label-filled">6</span>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                <div class="TreeRoot user-select-none overflow-hidden" style="position: relative;">
                                    <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="0350a8aa-721e-40b4-b1ea-7908acddfdf4">
                                        <div class="TreeNode from-group" data-key="0350a8aa-721e-40b4-b1ea-7908acddfdf4">
                                            <span class="TreeLabel TreeLabelName">
                                                <span class="TreeLabelNameText">
                                                    <span class="TreeLabelNameTextHeadline">My Empty Group</span>
                                                </span>
                                                <span class="TreeLabelCount label label-muted label-filled label-condensed">3</span>
                                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                                </span>
                                            </span>
                                        </div>
                                    </div>
                                    <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="b40aabcf-01f8-4be2-bc3d-9157cbdb395f">
                                        <div class="TreeNode from-group" data-key="b40aabcf-01f8-4be2-bc3d-9157cbdb395f">
                                            <span class="TreeLabel TreeLabelName">
                                                <span class="TreeLabelNameText">
                                                    <span class="TreeLabelNameTextHeadline">Truck Group East</span>
                                                </span>
                                                <span class="TreeLabelCount label label-muted label-filled label-condensed">5</span>
                                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                                </span>
                                            </span>
                                        </div>
                                    </div>
                                    <div class="TreeNodeContainer user-select-none overflow-hidden open" data-id="6ba7c2ec-8bd4-4470-98a4-313c9d33e8d5">
                                        <div class="TreeNode from-group" data-key="6ba7c2ec-8bd4-4470-98a4-313c9d33e8d5">
                                            <span class="TreeLabel TreeLabelName">
                                                <span class="TreeLabelNameText">
                                                    <span class="TreeLabelNameTextHeadline">Truck Group North</span>
                                                </span>
                                                <span class="TreeLabelCount label label-muted label-filled label-condensed">4</span>
                                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                                </span>
                                            </span>
                                        </div>
                                        <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d976">
                                            <span class="TreeLabel TreeLabelName">
                                                <span class="rioglyph rioglyph-bus">
                                                </span>
                                                <span class="TreeLabelNameText">
                                                    <span class="TreeLabelNameTextHeadline">N18-G259 / M-AN 1006</span>
                                                </span>
                                            </span>
                                        </div>
                                        <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d9729">
                                            <span class="TreeLabel TreeLabelName">
                                                <span class="rioglyph rioglyph-van">
                                                </span>
                                                <span class="TreeLabelNameText">
                                                    <span class="TreeLabelNameTextHeadline">N18-G545 / M-AN 1029</span>
                                                </span>
                                            </span>
                                        </div>
                                        <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d9711">
                                            <span class="TreeLabel TreeLabelName">
                                                <span class="rioglyph rioglyph-trailer">
                                                </span>
                                                <span class="TreeLabelNameText">
                                                    <span class="TreeLabelNameTextHeadline">N18-G632 / M-AN 1011</span>
                                                </span>
                                            </span>
                                        </div>
                                        <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d973">
                                            <span class="TreeLabel TreeLabelName">
                                                <span class="rioglyph rioglyph-bus">
                                                </span>
                                                <span class="TreeLabelNameText">
                                                    <span class="TreeLabelNameTextHeadline">N18-G845 / M-AN 1003</span>
                                                </span>
                                            </span>
                                        </div>
                                    </div>
                                    <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="722a5f86-eb6c-46cf-83da-3f8dbfbcca5e">
                                        <div class="TreeNode from-group" data-key="722a5f86-eb6c-46cf-83da-3f8dbfbcca5e">
                                            <span class="TreeLabel TreeLabelName">
                                                <span class="TreeLabelNameText">
                                                    <span class="TreeLabelNameTextHeadline">Truck Group South</span>
                                                </span>
                                                <span class="TreeLabelCount label label-muted label-filled label-condensed">7</span>
                                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                                </span>
                                            </span>
                                        </div>
                                    </div>
                                    <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="0250a8aa-721e-40b4-b1ea-7908acddfdf4">
                                        <div class="TreeNode from-group" data-key="0250a8aa-721e-40b4-b1ea-7908acddfdf4">
                                            <span class="TreeLabel TreeLabelName">
                                                <span class="TreeLabelNameText">
                                                    <span class="TreeLabelNameTextHeadline">Truck Group West</span>
                                                </span>
                                                <span class="TreeLabelCount label label-muted label-filled label-condensed">6</span>
                                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                                </span>
                                            </span>
                                        </div>
                                    </div>
                                    <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="static/unassignedTrucks">
                                        <div class="TreeNode from-group" data-key="static/unassignedTrucks">
                                            <span class="TreeLabel TreeLabelName">
                                                <span class="TreeLabelNameText">
                                                    <span class="TreeLabelNameTextHeadline">All my unassigned Trucks</span>
                                                </span>
                                                <span class="TreeLabelCount label label-muted label-filled label-condensed">5</span>
                                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                                </span>
                                            </span>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="scrollbar-track-horizontal" style="position: absolute; height: 6px; display: none;">
                        <div class="scrollbar-thumb-horizontal" style="position: relative; display: block; height: 100%;">
                        </div>
                    </div>
                    <div class="scrollbar-track-vertical" style="position: absolute; width: 6px; display: none;">
                        <div class="scrollbar-thumb-vertical" style="position: relative; display: block; width: 100%;">
                        </div>
                    </div>
                </div>
            </div>
            <div class="Resizer resize-horizontal resize-right">
            </div>
        </div>
    </div>
    <div>
        <div class="h6">Current category:</div>
        <ul>assets</ul>
        <div class="h6">Selected tree groups:</div>
        <ul>
        </ul>
        <div class="h6">Selected assets:</div>
        <ul>
        </ul>
        <div class="h6">Expanded tree groups:</div>
        <ul>
            <li>Truck Group North</li>
        </ul>
    </div>
</div>
```

#### Props: AssetTree

### AssetTree

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| fly | boolean | false | Defines if the component will overlap the body content. |
| resizable | boolean | true | Defines whether or not the sidebar is resizable. |
| bordered | boolean | false | Defines whether the component has a border or not. |
| width | number | 350 | Defines the width of the component. The value is set as inline style. Note: when component is resizable it will take the provided width in px only and convert it to number in case. |
| minWidth | number | 100 | Defines the minimum width of the component in px that will take effect when resizing. |
| maxWidth | number | 0 | Defines the maximum width of the component in px that will take effect when resizing. |
| height | number | — | Defines the height of the component in px. |
| isOpen | boolean | true | Defines whether the component is open or not. |
| onToggleTree | (isOpen: boolean) => void | () => {} | Callback for when the tree visibility is toggled. |
| currentCategoryId | string | — | The id of the category which is currently active and shall be shown. |
| onCategoryChange | (selectedCategoryId: string) => void | () => {} | Callback for handling change of category. |
| onResizeEnd | VoidFunction | () => {} | Callback for when the resize is done. |
| useOffscreen | boolean | false | Defines whether the tree components are rendered offscreen and kept mounted in the DOM. |
| className | string | — | Additional classes added on the wrapper element. |

#### Props: TreeCategory

### TreeCategory

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| id | string | — | A unique identifier for that category. |
| icon | string | — | The rioglyph icon name for that category. |
| label | string \| React.ReactNode | — | The optional label for the category which will be shown in a tooltip. |
| hasSelection | boolean | — | Defines whether or not a selection indicator should be shown. |

#### Props: Tree

### Tree

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| groups | TreeGroup[] | [] | The list of groups of the items. If no groups are provided all items are rendered as flat list. |
| └id | string | — | A unique identifier of a group. |
| └name | string \| React.ReactNode | — | The name of a group. |
| └position | 'last' | — | Can be set to "last" to enforce the last position in the tree. |
| └disabled | boolean | — | Disallows the selection of the group itself. |
| └icon | string | — | The rioglyph icon name for a group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └expandedIcon | string | — | The rioglyph icon name for a expanded group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └className | string | — | Additional classes added to the group element. |
| items | TreeItem[] | [] | The list of items. |
| └id | string | — | A unique identifier of an item. |
| └name | string \| TreeItemName | — | The name of an item. Either it is a plain string or an object composed of: firstName and lastName where lastName is mandatory. |
| └info | string \| React.ReactNode | — | The subline of an item. This can e used to show additional information for that item. |
| └type | string | — | The primary type of the item. This is also used as the fallback icon name and refers to the name of the respective rioglyph icon (excluding the rioglyph- prefix). |
| └icon | string \| null | — | Optional icon override for the item. If set to a string (e.g. 'truck'), this icon will be used explicitly. If set to undefined, the type property will be used as the fallback icon. If set to null, no icon will be rendered, even if type is defined. This allows full control over the icon behavior while maintaining backward compatibility with type-based icons. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └subType | string | — | Optional sub-type of the item. This refers to the name of an additional rioglyph icon (excluding the rioglyph- prefix), typically used to render a secondary icon next to the primary one (Note: for fuel types better use the pairIcon prop). |
| └pairIcon | string \| null \| undefined | — | Optional pair icon override for the subType. If set to a string (e.g. 'fuel-gas'), this icon will be used explicitly. If set to undefined, the subType property will be used as the fallback icon. If set to null, no icon will be rendered, even if subType is defined. This allows full control over the icon behavior while maintaining backward compatibility with subType-based icons. |
| └groupIds | string[] | [] | List of group ids the items is associated with. |
| └className | string | — | Additional classes added to the item element. |
| selectedGroups | string[] | [] | List of selected group ids. |
| selectedItems | string[] | [] | List of selected item ids. |
| onSelectionChange | ({ items, groups }: SelectionChangeResponse) => void | — | Merged Callback for item and group selection changes. It responds with a selection object that contains the selected itemIds and groupIds: { items: [], groups: [] } |
| hasMultiselect | boolean | true | Defines the selection behavior of the tree. |
| showRadioButtons | boolean | false | Defines if the single selection should also show radios. |
| hideSearch | boolean | false | Defines whether or not the built-in Search is shown. |
| searchPlaceholder | string | — | The text used as placeholder for the search input. |
| onSearchChange | (value: string) => void | — | Callback for when the search value changes. |
| search | React.ReactNode | — | Used to define custom search component which replaces the built-in search. |
| summary | React.ReactNode | — | Used to define custom asset type counter component which replaces the built-in summary. |
| hideSummary | boolean | false | Defines whether a summary is shown. |
| onTypeFilterChange | (currentTypes: string[]) => void | — | Callback triggered when the built-in asset type filter changes. This is only available when the default summary is used. |
| hideTreeHead | boolean | false | Defines whether the entire area below the search field is shown or not. Note: Disabling the tree head will hide the select all checkbox and the tree options as well as the tree summary. |
| treeHeaderContent | React.ReactElement | — | Additional custom content that is rendered at the top of the tree component. This can be used for nav pills. |
| scrollHeight | number | — | Defines the max-height of the scrollable list. |
| expandedGroups | string[] | — | List of group ids which are expanded. |
| onExpandGroupsChange | (newExpandedGroups: string[]) => void | — | Callback function triggered when a group expands or collapses. |
| showEmptyGroups | boolean | true | Defines whether empty groups are shown or not. |
| treeOptions | React.ReactNode[] | — | Component to offer customization options for the tree. |
| treeOptionsTooltip | React.ReactNode | — | Tooltip content for the tree options dropdown. |
| disableAnimation | boolean | false | Disables animation when filtering or using search |
| virtualizeThreshold | number | 50 | The number of items (including groups and children) used for virtualizing the tree. |
| overscan | number | 5 | The number of items rendered beyond the visible area of a virtualized tree. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSearch

### TreeSearch

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| value | string | — | The search value to be shown and used for the search. |
| onChange | (newValue: string, event: React.ChangeEvent \| React.MouseEvent) => void | () => {} | Callback for when the search value changes. |
| placeholder | string | — | The placeholder text used for the input field. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSummary

### TreeSummary

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| assetCounts | TreeSummaryCounts | — | The object containing various asset type counter. |
| └truck | number | — | The amount of trucks |
| └trailer | number | — | The amount of trailers |
| └bus | number | — | The amount of buses |
| └van | number | — | The amount of vans |
| └car | number | — | The amount of cars |
| └driver | number | — | The amount of drivers |
| gridCols | number | 4 | The number of grid columns used for the built-in TreeSummaryRow. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSummaryRow

### TreeSummaryRow

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| gridCols | number | 4 | Defined the number of grid columns for a single row. Note, when the amount of children exceed the columns it will wrap around to a new line. |

#### Props: TypeCounter

### TypeCounter

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| type | string | — | The item type for that counter. This will be used as a return value for the onClick callback. |
| icon | string | — | The icon name. Note, when using the built-in generic type counter, the icon name will the same as the item type. So make sure there is a corresponding icon for the defined type. |
| isActive | boolean | — | Sets the active styling if active |
| hasFilter | boolean | false | Should be set when there is a type filter set in the tree to style the counter accordingly. |
| enableActivity | boolean | false | Allows for interactivity. Use this prop when you allow clicking on the counter. |
| hideOnZero | boolean | false | Defines if the counter is rendered at all when the value is not defined ot 0. |
| onClick | (type: string) => void | — | Callback function when the counter is clicked. It returns the type value. Make sure the "type" prop is defined to receive the value in the callback. |
| value | string \| React.ReactNode \| number | — | A custom value to be shown in the counter. |

#### Props: TreeOption

### TreeOption

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| isChecked | boolean | false | Defines whether the option is set. |
| onChange | (event: React.MouseEvent<HTMLDivElement>) => void | — | Callback triggered when option is selected. |
| label | string \| React.ReactNode | — | The label for the option. |
| className | string | — | Additional classes added to the wrapping element. |

## AssetTree with multiple asset filter in summary

When using fuel filter, please check out the fuel type utils that ease the implementation of mapping vehicle fuel types to common fuel type groups.

### Example: Example 3

3
8
6
3

9
2
7
1
1

Mixed Vehicles 14

Vehicle-1032 Debug: lpg

Vehicle-1530 Debug: diesel

Vehicle-1885 Debug: electric

Vehicle-2261 Debug: electric

Vehicle-3321 Debug: electric

Vehicle-6234 Debug: gas

Vehicle-6675 Debug: gas

Vehicle-6884 Debug: dual_fuel_diesel_cng

Vehicle-7323 Debug: hydrogen

Vehicle-8654 Debug: diesel

Vehicle-8759 Debug: electric

Selected groups:

Selected vehicles:

Expanded groups:
Mixed Vehicles

#### React (tsx)

```tsx
import { useMemo, useState } from 'react';
import { isEmpty, random } from 'es-toolkit/compat';
import { faker } from '@faker-js/faker';

import AssetTree from '@rio-cloud/rio-uikit/AssetTree';
import TreeCategory from '@rio-cloud/rio-uikit/TreeCategory';
import Tree, {
    type TreeGroup,
    type TreeItem,
    type SelectionChangeResponse,
    getTypeCounts,
} from '@rio-cloud/rio-uikit/Tree';
import TreeOption from '@rio-cloud/rio-uikit/TreeOption';
import TreeSummary, { type TreeSummaryCounts } from '@rio-cloud/rio-uikit/TreeSummary';
import TreeSummaryRow from '@rio-cloud/rio-uikit/TreeSummaryRow';
import TypeCounter from '@rio-cloud/rio-uikit/TypeCounter';
import {
    countFuelTypeGroups,
    filterByFuelTypeGroup,
    fuelTypeGroups,
    getFuelIcon,
    getFuelTypeGroupIcon,
    type FuelType,
    type FuelTypeGroup,
} from '@rio-cloud/rio-uikit/fuelTypeUtils';

const toggleListItem = (list: string[], item: string) => {
    const set = new Set(list);
    if (set.has(item)) {
        set.delete(item);
    } else {
        set.add(item);
    }
    return [...set];
};

const truckGroups: TreeGroup[] = [
    {
        id: 'group-1',
        name: 'Mixed Vehicles',
    },
    {
        id: 'unassigned-group',
        name: 'Ungrouped',
        position: 'last',
    },
];

const assetTypes = ['truck', 'bus', 'van', 'car'];
const fuelTypes = ['diesel', 'electric', 'gas', 'hydrogen', 'cng', 'lpg', 'dual_fuel_diesel_cng', 'heavy_fuel_oil'];

const getVehicles = (withSubType = true): TreeItem[] =>
    Array.from({ length: 20 }, (_, index) => {
        const fuelType = withSubType ? faker.helpers.arrayElement(fuelTypes) : undefined;
        return {
            id: `010191ac-d06d-4567-b13a-7b7fd85d97${index}`,
            name: `Vehicle-${random(1000, 9999)}`,
            info: <span>Debug: {fuelType}</span>,
            type: faker.helpers.arrayElement(assetTypes),
            subType: fuelType, // subType cannot be used as icon here anymore
            pairIcon: getFuelIcon(fuelType),
            groupIds: [faker.helpers.arrayElement(truckGroups).id],
        };
    });

const defaultExpandedTruckGroups = ['group-1'];

const getAssetTypeCounts = getTypeCounts;
const getFuelTypeCounts = (items: TreeItem[]) => countFuelTypeGroups(items, item => item.subType as FuelType);

const AssetTreeExample = () => {
    const [selectedTruckGroupIds, setSelectedTruckGroupIds] = useState<string[]>([]);
    const [selectedTruckIds, setSelectedTruckIds] = useState<string[]>([]);
    const [expandedTruckGroups, setExpandedTruckGroups] = useState(defaultExpandedTruckGroups);

    const [isTreeOpen, setIsTreeOpen] = useState(true);

    const [showEmptyGroups, setShowEmptyGroups] = useState(false);
    const [showAssetGroups, setShowAssetGroups] = useState(true);
    const [showFuelType, setShowFuelType] = useState(true);

    const [activeAssetTypeFilter, setActiveAssetTypeFilter] = useState<string[]>([]);
    const [activeFuelTypeGroupFilter, setActiveFuelTypeGroupFilter] = useState<string[]>([]);

    const [counters, setCounters] = useState<TreeSummaryCounts>({});
    const [fuelCounters, setFuelCounters] = useState<Record<string, number>>({});

    const items = useMemo(() => {
        // Regenerate vehicles to omit the fuel type data used for the sub type
        const result = getVehicles(showFuelType);

        // Count again all vehicle types and sub types
        setCounters(getAssetTypeCounts(result));
        setFuelCounters(getFuelTypeCounts(result));

        return result;
    }, [showFuelType]);

    const filteredItems = useMemo(() => {
        let result = items;

        // filter by asset type
        if (!isEmpty(activeAssetTypeFilter)) {
            result = result.filter(item => activeAssetTypeFilter.includes(item.type));
        }

        // filter by fuel type
        if (!isEmpty(activeFuelTypeGroupFilter)) {
            result = filterByFuelTypeGroup(
                result,
                activeFuelTypeGroupFilter as FuelTypeGroup[],
                item => item.subType as FuelType
            );
        }

        return result;
    }, [items, activeAssetTypeFilter, activeFuelTypeGroupFilter]);

    const handleSelectTruck = ({ items, groups }: SelectionChangeResponse) => {
        setSelectedTruckIds(items);
        setSelectedTruckGroupIds(groups);
    };

    const handleExpandTruckGroups = (newExpandedTruckGroups: string[]) =>
        setExpandedTruckGroups(newExpandedTruckGroups);

    const handleToggleTree = (toggle: boolean) => setIsTreeOpen(toggle);
    const handleToggleEmptyGroups = () => setShowEmptyGroups(!showEmptyGroups);
    const handleToggleAssetGroups = () => setShowAssetGroups(!showAssetGroups);
    const handleToggleFuelType = () => {
        setShowFuelType(!showFuelType);
        setActiveFuelTypeGroupFilter([]);
    };

    const handleSearchChange = (searchValue: string) => {
        const filteredAssets = filteredItems.filter(item =>
            (item.name as string).toLowerCase().includes(searchValue.toLowerCase())
        );
    };

    const handleAssetTypeFilterChange = (assetTypeFilter: string) => {
        setActiveAssetTypeFilter(toggleListItem(activeAssetTypeFilter, assetTypeFilter));
    };

    const handleFuelTypeGroupFilterChange = (fuelTypeGroupFilter: string) => {
        setActiveFuelTypeGroupFilter(toggleListItem(activeFuelTypeGroupFilter, fuelTypeGroupFilter));
    };

    const renderSelectedItemsOfList = (selectedItemIds: string[], list: TreeGroup[] | TreeItem[]) =>
        selectedItemIds.map(selectedItemId => {
            const result = list.find(listItem => listItem.id === selectedItemId);
            if (result) {
                return <li key={selectedItemId}>{`${result.name}`}</li>;
            }
            return null;
        });

    return (
        <div className='display-flex flex-wrap gap-25 overflow-auto'>
            <AssetTree
                bordered
                minWidth={300}
                maxWidth={450}
                height={500}
                isOpen={isTreeOpen}
                onToggleTree={handleToggleTree}
                currentCategoryId='trucks'
                useOffscreen
            >
                <TreeCategory
                    key='trucks'
                    id='trucks'
                    label='Assets'
                    icon='rioglyph-truck'
                    hasSelection={!isEmpty(selectedTruckIds) || !isEmpty(selectedTruckGroupIds)}
                >
                    <Tree
                        groups={showAssetGroups ? truckGroups : []}
                        items={filteredItems}
                        expandedGroups={expandedTruckGroups}
                        onExpandGroupsChange={handleExpandTruckGroups}
                        selectedGroups={selectedTruckGroupIds}
                        selectedItems={selectedTruckIds}
                        onSelectionChange={handleSelectTruck}
                        searchPlaceholder='Find vehicle'
                        showEmptyGroups={showEmptyGroups}
                        onSearchChange={handleSearchChange}
                        virtualizeThreshold={14}
                        summary={
                            <TreeSummary>
                                <TreeSummaryRow>
                                    {assetTypes.map(assetType => (
                                        <TypeCounter
                                            key={assetType}
                                            type={assetType}
                                            icon={`${assetType}-baseline`}
                                            value={(counters as Record<string, number>)[assetType]}
                                            isActive={activeAssetTypeFilter.includes(assetType)}
                                            hasFilter={!isEmpty(activeAssetTypeFilter)}
                                            onClick={handleAssetTypeFilterChange}
                                            enableActivity
                                            hideOnZero
                                        />
                                    ))}
                                </TreeSummaryRow>
                                <TreeSummaryRow>
                                    {showFuelType &&
                                        fuelTypeGroups.map(fuelTypeGroup => (
                                            <TypeCounter
                                                key={fuelTypeGroup}
                                                type={fuelTypeGroup}
                                                icon={getFuelTypeGroupIcon(fuelTypeGroup)}
                                                value={fuelCounters[fuelTypeGroup]}
                                                isActive={activeFuelTypeGroupFilter.includes(fuelTypeGroup)}
                                                hasFilter={!isEmpty(activeFuelTypeGroupFilter)}
                                                onClick={handleFuelTypeGroupFilterChange}
                                                enableActivity
                                                hideOnZero
                                            />
                                        ))}
                                </TreeSummaryRow>
                            </TreeSummary>
                        }
                        treeOptionsTooltip='Customize view'
                        treeOptions={[
                            <TreeOption
                                key='emptyGroupsToggle'
                                label='Show empty groups'
                                isChecked={showEmptyGroups}
                                onChange={handleToggleEmptyGroups}
                            />,
                            <TreeOption
                                key='assetGroupsToggle'
                                label='Show groups'
                                isChecked={showAssetGroups}
                                onChange={handleToggleAssetGroups}
                            />,
                            <hr key='hr' className='width-100pct margin-y-5' />,
                            <TreeOption
                                key='fuelTypeToggle'
                                label='Show alternative fuel types'
                                isChecked={showFuelType}
                                onChange={handleToggleFuelType}
                            />,
                        ]}
                    />
                </TreeCategory>
            </AssetTree>
            <div>
                <div className='h6'>Selected groups:</div>
                <ul>{renderSelectedItemsOfList(selectedTruckGroupIds, truckGroups)}</ul>
                <div className='h6'>Selected vehicles:</div>
                <ul>{renderSelectedItemsOfList(selectedTruckIds, items)}</ul>
                <div className='h6'>Expanded groups:</div>
                <ul>{renderSelectedItemsOfList(expandedTruckGroups, truckGroups)}</ul>
            </div>
        </div>
    );
};

export default AssetTreeExample;
```

#### HTML (html)

```html
<div class="display-flex flex-wrap gap-25 overflow-auto">
    <div class="AssetTree border fluid" style="width: 350px; height: 500px;">
        <div class="AssetTreeResizeLimit" style="left: 450px;">
        </div>
        <div class="AssetTreeContent">
            <div class="TreeSidebar">
                <ul class="TreeSidebarNavigation">
                    <li class="active">
                        <div class="selection-bubble">
                            <span class="rioglyph rioglyph-truck">
                            </span>
                        </div>
                    </li>
                </ul>
                <div class="TreeSidebarToggle">
                    <span class="rioglyph rioglyph-chevron-left">
                    </span>
                </div>
            </div>
            <div class="AssetTreeBody scrollbar-fly-in smooth-scrollbar-wrapper" style="position: relative; overflow: hidden; width: 100%; height: 100%;">
                <div class="scrollbar-view" style="position: absolute; inset: 0px; overflow: scroll; margin-right: 0px; margin-bottom: 0px;">
                    <div class="scrollbar-content-wrapper">
                        <div class="TreeOffscreenWrapper">
                            <div class="Tree">
                                <div class="TreeHeader">
                                    <div class="TreeSearch">
                                        <div class="input-group flex-1-0">
                                            <span class="input-group-addon">
                                                <span class="rioglyph rioglyph-search" aria-hidden="true">
                                                </span>
                                            </span>
                                            <div class="ClearableInput input-group">
                                                <input placeholder="Find vehicle" class="form-control" type="text" tabindex="0" value="">
                                                <span class="clearButton hide">
                                                    <span class="clearButtonIcon rioglyph rioglyph-remove-sign">
                                                    </span>
                                                </span>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="TreeHead display-flex gap-5 padding-15">
                                        <div class="border border-right-only hidden-empty padding-right-10 margin-right-2">
                                            <div class="TreeSelectAll display-flex align-items-center">
                                                <label class="checkbox margin-top--1" tabindex="0">
                                                    <input type="checkbox" class="margin-top--1">
                                                    <span class="checkbox-text">
                                                    </span>
                                                </label>
                                            </div>
                                        </div>
                                        <div class="display-flex justify-content-between align-items-start width-100pct">
                                            <div class="TreeSummary display-flex flex-wrap align-items-center gap-10 padding-left-3">
                                                <div class="TreeSummaryRow display-grid grid-cols-4 gap-10">
                                                    <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                        <span class="rioglyph rioglyph-truck-baseline text-size-16 margin-right-2">
                                                        </span>
                                                        <span class="TreeLabelCount label label-condensed label-muted label-filled">3</span>
                                                    </div>
                                                    <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                        <span class="rioglyph rioglyph-bus-baseline text-size-16 margin-right-2">
                                                        </span>
                                                        <span class="TreeLabelCount label label-condensed label-muted label-filled">8</span>
                                                    </div>
                                                    <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                        <span class="rioglyph rioglyph-van-baseline text-size-16 margin-right-2">
                                                        </span>
                                                        <span class="TreeLabelCount label label-condensed label-muted label-filled">6</span>
                                                    </div>
                                                    <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                        <span class="rioglyph rioglyph-car-baseline text-size-16 margin-right-2">
                                                        </span>
                                                        <span class="TreeLabelCount label label-condensed label-muted label-filled">3</span>
                                                    </div>
                                                </div>
                                                <div class="TreeSummaryRow display-grid grid-cols-4 gap-10">
                                                    <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                        <span class="rioglyph rioglyph-fuel-liquid text-size-16 margin-right-2">
                                                        </span>
                                                        <span class="TreeLabelCount label label-condensed label-muted label-filled">9</span>
                                                    </div>
                                                    <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                        <span class="rioglyph rioglyph-fuel-gas text-size-16 margin-right-2">
                                                        </span>
                                                        <span class="TreeLabelCount label label-condensed label-muted label-filled">2</span>
                                                    </div>
                                                    <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                        <span class="rioglyph rioglyph-fuel-electric text-size-16 margin-right-2">
                                                        </span>
                                                        <span class="TreeLabelCount label label-condensed label-muted label-filled">7</span>
                                                    </div>
                                                    <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                        <span class="rioglyph rioglyph-fuel-hydrogen text-size-16 margin-right-2">
                                                        </span>
                                                        <span class="TreeLabelCount label label-condensed label-muted label-filled">1</span>
                                                    </div>
                                                    <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                        <span class="rioglyph rioglyph-fuel-mix text-size-16 margin-right-2">
                                                        </span>
                                                        <span class="TreeLabelCount label label-condensed label-muted label-filled">1</span>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                        <div>
                                            <div class="dropdown btn-group TreeHeaderOptions height-20">
                                                <button type="button" id="9uzjfkuoqvt" class="btn btn-default btn-sm btn-icon-only btn-component dropdown-toggle hover-bg-white border-none text-color-gray hover-text-color-dark" tabindex="0">
                                                    <span class="rioglyph rioglyph-option-vertical" aria-hidden="true">
                                                    </span>
                                                </button>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                <div class="TreeRoot user-select-none overflow-hidden" style="position: relative;">
                                    <div class="tree-virtual-scrollbar scrollbar-fly-in smooth-scrollbar-wrapper" style="position: relative; overflow: hidden; width: 100%; height: 100%;">
                                        <div class="scrollbar-view" style="position: absolute; inset: 0px; overflow: scroll; margin-right: 0px; margin-bottom: 0px;">
                                            <div class="scrollbar-content-wrapper">
                                                <div class="grouped-list" style="height: 825px; position: relative;">
                                                    <div data-index="0" class="virtualized-tree-item group-item " style="position: absolute; top: 0px; left: 0px; width: 100%; height: 41px; transform: translateY(0px);">
                                                        <div class="TreeNodeContainer user-select-none overflow-hidden open" data-id="group-1">
                                                            <div class="TreeNode from-group" data-key="group-1">
                                                                <label class="checkbox TreeCheckbox" tabindex="0">
                                                                    <input type="checkbox" class="TreeCheckbox">
                                                                    <span class="checkbox-text">
                                                                    </span>
                                                                </label>
                                                                <span class="TreeLabel TreeLabelName">
                                                                    <span class="TreeLabelNameText">
                                                                        <span class="TreeLabelNameTextHeadline">Mixed Vehicles</span>
                                                                    </span>
                                                                    <span class="TreeLabelCount label label-muted label-filled label-condensed">14</span>
                                                                    <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                                                    </span>
                                                                </span>
                                                            </div>
                                                        </div>
                                                    </div>
                                                    <div data-index="1" class="virtualized-tree-item leaf-item " style="position: absolute; top: 0px; left: 0px; width: 100%; height: 54px; transform: translateY(41px);">
                                                        <div class="TreeNodeContainer user-select-none overflow-hidden open">
                                                            <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d9710">
                                                                <label class="checkbox TreeCheckbox" tabindex="0">
                                                                    <input type="checkbox" class="TreeCheckbox">
                                                                    <span class="checkbox-text">
                                                                    </span>
                                                                </label>
                                                                <span class="TreeLabel TreeLabelName">
                                                                    <span class="rioglyph-icon-pair">
                                                                        <span class="rioglyph rioglyph-van">
                                                                        </span>
                                                                        <span class="rioglyph rioglyph-fuel-gas">
                                                                        </span>
                                                                    </span>
                                                                    <span class="TreeLabelNameText">
                                                                        <span class="TreeLabelNameTextHeadline">Vehicle-1032</span>
                                                                        <span class="TreeLabelNameTextSubline">
                                                                            <span>Debug: lpg</span>
                                                                        </span>
                                                                    </span>
                                                                </span>
                                                            </div>
                                                        </div>
                                                    </div>
                                                    <div data-index="2" class="virtualized-tree-item leaf-item " style="position: absolute; top: 0px; left: 0px; width: 100%; height: 54px; transform: translateY(95px);">
                                                        <div class="TreeNodeContainer user-select-none overflow-hidden open">
                                                            <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d972">
                                                                <label class="checkbox TreeCheckbox" tabindex="0">
                                                                    <input type="checkbox" class="TreeCheckbox">
                                                                    <span class="checkbox-text">
                                                                    </span>
                                                                </label>
                                                                <span class="TreeLabel TreeLabelName">
                                                                    <span class="rioglyph-icon-pair">
                                                                        <span class="rioglyph rioglyph-bus">
                                                                        </span>
                                                                        <span class="rioglyph rioglyph-fuel-liquid">
                                                                        </span>
                                                                    </span>
                                                                    <span class="TreeLabelNameText">
                                                                        <span class="TreeLabelNameTextHeadline">Vehicle-1530</span>
                                                                        <span class="TreeLabelNameTextSubline">
                                                                            <span>Debug: diesel</span>
                                                                        </span>
                                                                    </span>
                                                                </span>
                                                            </div>
                                                        </div>
                                                    </div>
                                                    <div data-index="3" class="virtualized-tree-item leaf-item " style="position: absolute; top: 0px; left: 0px; width: 100%; height: 54px; transform: translateY(149px);">
                                                        <div class="TreeNodeContainer user-select-none overflow-hidden open">
                                                            <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d976">
                                                                <label class="checkbox TreeCheckbox" tabindex="0">
                                                                    <input type="checkbox" class="TreeCheckbox">
                                                                    <span class="checkbox-text">
                                                                    </span>
                                                                </label>
                                                                <span class="TreeLabel TreeLabelName">
                                                                    <span class="rioglyph-icon-pair">
                                                                        <span class="rioglyph rioglyph-van">
                                                                        </span>
                                                                        <span class="rioglyph rioglyph-fuel-electric">
                                                                        </span>
                                                                    </span>
                                                                    <span class="TreeLabelNameText">
                                                                        <span class="TreeLabelNameTextHeadline">Vehicle-1885</span>
                                                                        <span class="TreeLabelNameTextSubline">
                                                                            <span>Debug: electric</span>
                                                                        </span>
                                                                    </span>
                                                                </span>
                                                            </div>
                                                        </div>
                                                    </div>
                                                    <div data-index="4" class="virtualized-tree-item leaf-item " style="position: absolute; top: 0px; left: 0px; width: 100%; height: 54px; transform: translateY(203px);">
                                                        <div class="TreeNodeContainer user-select-none overflow-hidden open">
                                                            <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d970">
                                                                <label class="checkbox TreeCheckbox" tabindex="0">
                                                                    <input type="checkbox" class="TreeCheckbox">
                                                                    <span class="checkbox-text">
                                                                    </span>
                                                                </label>
                                                                <span class="TreeLabel TreeLabelName">
                                                                    <span class="rioglyph-icon-pair">
                                                                        <span class="rioglyph rioglyph-van">
                                                                        </span>
                                                                        <span class="rioglyph rioglyph-fuel-electric">
                                                                        </span>
                                                                    </span>
                                                                    <span class="TreeLabelNameText">
                                                                        <span class="TreeLabelNameTextHeadline">Vehicle-2261</span>
                                                                        <span class="TreeLabelNameTextSubline">
                                                                            <span>Debug: electric</span>
                                                                        </span>
                                                                    </span>
                                                                </span>
                                                            </div>
                                                        </div>
                                                    </div>
                                                    <div data-index="5" class="virtualized-tree-item leaf-item " style="position: absolute; top: 0px; left: 0px; width: 100%; height: 54px; transform: translateY(257px);">
                                                        <div class="TreeNodeContainer user-select-none overflow-hidden open">
                                                            <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d9719">
                                                                <label class="checkbox TreeCheckbox" tabindex="0">
                                                                    <input type="checkbox" class="TreeCheckbox">
                                                                    <span class="checkbox-text">
                                                                    </span>
                                                                </label>
                                                                <span class="TreeLabel TreeLabelName">
                                                                    <span class="rioglyph-icon-pair">
                                                                        <span class="rioglyph rioglyph-bus">
                                                                        </span>
                                                                        <span class="rioglyph rioglyph-fuel-electric">
                                                                        </span>
                                                                    </span>
                                                                    <span class="TreeLabelNameText">
                                                                        <span class="TreeLabelNameTextHeadline">Vehicle-3321</span>
                                                                        <span class="TreeLabelNameTextSubline">
                                                                            <span>Debug: electric</span>
                                                                        </span>
                                                                    </span>
                                                                </span>
                                                            </div>
                                                        </div>
                                                    </div>
                                                    <div data-index="6" class="virtualized-tree-item leaf-item " style="position: absolute; top: 0px; left: 0px; width: 100%; height: 54px; transform: translateY(311px);">
                                                        <div class="TreeNodeContainer user-select-none overflow-hidden open">
                                                            <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d9715">
                                                                <label class="checkbox TreeCheckbox" tabindex="0">
                                                                    <input type="checkbox" class="TreeCheckbox">
                                                                    <span class="checkbox-text">
                                                                    </span>
                                                                </label>
                                                                <span class="TreeLabel TreeLabelName">
                                                                    <span class="rioglyph-icon-pair">
                                                                        <span class="rioglyph rioglyph-car">
                                                                        </span>
                                                                        <span class="rioglyph rioglyph-fuel-liquid">
                                                                        </span>
                                                                    </span>
                                                                    <span class="TreeLabelNameText">
                                                                        <span class="TreeLabelNameTextHeadline">Vehicle-6234</span>
                                                                        <span class="TreeLabelNameTextSubline">
                                                                            <span>Debug: gas</span>
                                                                        </span>
                                                                    </span>
                                                                </span>
                                                            </div>
                                                        </div>
                                                    </div>
                                                    <div data-index="7" class="virtualized-tree-item leaf-item " style="position: absolute; top: 0px; left: 0px; width: 100%; height: 54px; transform: translateY(365px);">
                                                        <div class="TreeNodeContainer user-select-none overflow-hidden open">
                                                            <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d9716">
                                                                <label class="checkbox TreeCheckbox" tabindex="0">
                                                                    <input type="checkbox" class="TreeCheckbox">
                                                                    <span class="checkbox-text">
                                                                    </span>
                                                                </label>
                                                                <span class="TreeLabel TreeLabelName">
                                                                    <span class="rioglyph-icon-pair">
                                                                        <span class="rioglyph rioglyph-bus">
                                                                        </span>
                                                                        <span class="rioglyph rioglyph-fuel-liquid">
                                                                        </span>
                                                                    </span>
                                                                    <span class="TreeLabelNameText">
                                                                        <span class="TreeLabelNameTextHeadline">Vehicle-6675</span>
                                                                        <span class="TreeLabelNameTextSubline">
                                                                            <span>Debug: gas</span>
                                                                        </span>
                                                                    </span>
                                                                </span>
                                                            </div>
                                                        </div>
                                                    </div>
                                                    <div data-index="8" class="virtualized-tree-item leaf-item " style="position: absolute; top: 0px; left: 0px; width: 100%; height: 54px; transform: translateY(419px);">
                                                        <div class="TreeNodeContainer user-select-none overflow-hidden open">
                                                            <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d9712">
                                                                <label class="checkbox TreeCheckbox" tabindex="0">
                                                                    <input type="checkbox" class="TreeCheckbox">
                                                                    <span class="checkbox-text">
                                                                    </span>
                                                                </label>
                                                                <span class="TreeLabel TreeLabelName">
                                                                    <span class="rioglyph-icon-pair">
                                                                        <span class="rioglyph rioglyph-bus">
                                                                        </span>
                                                                        <span class="rioglyph rioglyph-fuel-mix">
                                                                        </span>
                                                                    </span>
                                                                    <span class="TreeLabelNameText">
                                                                        <span class="TreeLabelNameTextHeadline">Vehicle-6884</span>
                                                                        <span class="TreeLabelNameTextSubline">
                                                                            <span>Debug: dual_fuel_diesel_cng</span>
                                                                        </span>
                                                                    </span>
                                                                </span>
                                                            </div>
                                                        </div>
                                                    </div>
                                                    <div data-index="9" class="virtualized-tree-item leaf-item " style="position: absolute; top: 0px; left: 0px; width: 100%; height: 54px; transform: translateY(473px);">
                                                        <div class="TreeNodeContainer user-select-none overflow-hidden open">
                                                            <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d979">
                                                                <label class="checkbox TreeCheckbox" tabindex="0">
                                                                    <input type="checkbox" class="TreeCheckbox">
                                                                    <span class="checkbox-text">
                                                                    </span>
                                                                </label>
                                                                <span class="TreeLabel TreeLabelName">
                                                                    <span class="rioglyph-icon-pair">
                                                                        <span class="rioglyph rioglyph-bus">
                                                                        </span>
                                                                        <span class="rioglyph rioglyph-fuel-hydrogen">
                                                                        </span>
                                                                    </span>
                                                                    <span class="TreeLabelNameText">
                                                                        <span class="TreeLabelNameTextHeadline">Vehicle-7323</span>
                                                                        <span class="TreeLabelNameTextSubline">
                                                                            <span>Debug: hydrogen</span>
                                                                        </span>
                                                                    </span>
                                                                </span>
                                                            </div>
                                                        </div>
                                                    </div>
                                                    <div data-index="10" class="virtualized-tree-item leaf-item " style="position: absolute; top: 0px; left: 0px; width: 100%; height: 54px; transform: translateY(527px);">
                                                        <div class="TreeNodeContainer user-select-none overflow-hidden open">
                                                            <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d978">
                                                                <label class="checkbox TreeCheckbox" tabindex="0">
                                                                    <input type="checkbox" class="TreeCheckbox">
                                                                    <span class="checkbox-text">
                                                                    </span>
                                                                </label>
                                                                <span class="TreeLabel TreeLabelName">
                                                                    <span class="rioglyph-icon-pair">
                                                                        <span class="rioglyph rioglyph-bus">
                                                                        </span>
                                                                        <span class="rioglyph rioglyph-fuel-liquid">
                                                                        </span>
                                                                    </span>
                                                                    <span class="TreeLabelNameText">
                                                                        <span class="TreeLabelNameTextHeadline">Vehicle-8654</span>
                                                                        <span class="TreeLabelNameTextSubline">
                                                                            <span>Debug: diesel</span>
                                                                        </span>
                                                                    </span>
                                                                </span>
                                                            </div>
                                                        </div>
                                                    </div>
                                                    <div data-index="11" class="virtualized-tree-item leaf-item " style="position: absolute; top: 0px; left: 0px; width: 100%; height: 54px; transform: translateY(581px);">
                                                        <div class="TreeNodeContainer user-select-none overflow-hidden open">
                                                            <div class="TreeLeaf form-group margin-bottom-0" data-key="010191ac-d06d-4567-b13a-7b7fd85d9714">
                                                                <label class="checkbox TreeCheckbox" tabindex="0">
                                                                    <input type="checkbox" class="TreeCheckbox">
                                                                    <span class="checkbox-text">
                                                                    </span>
                                                                </label>
                                                                <span class="TreeLabel TreeLabelName">
                                                                    <span class="rioglyph-icon-pair">
                                                                        <span class="rioglyph rioglyph-truck">
                                                                        </span>
                                                                        <span class="rioglyph rioglyph-fuel-electric">
                                                                        </span>
                                                                    </span>
                                                                    <span class="TreeLabelNameText">
                                                                        <span class="TreeLabelNameTextHeadline">Vehicle-8759</span>
                                                                        <span class="TreeLabelNameTextSubline">
                                                                            <span>Debug: electric</span>
                                                                        </span>
                                                                    </span>
                                                                </span>
                                                            </div>
                                                        </div>
                                                    </div>
                                                </div>
                                            </div>
                                        </div>
                                        <div class="scrollbar-track-horizontal" style="position: absolute; height: 6px; display: none;">
                                            <div class="scrollbar-thumb-horizontal" style="position: relative; display: block; height: 100%;">
                                            </div>
                                        </div>
                                        <div class="scrollbar-track-vertical" style="position: absolute; width: 6px; display: none;">
                                            <div class="scrollbar-thumb-vertical" style="position: relative; display: block; width: 100%;">
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="scrollbar-track-horizontal" style="position: absolute; height: 6px; display: none;">
                    <div class="scrollbar-thumb-horizontal" style="position: relative; display: block; height: 100%;">
                    </div>
                </div>
                <div class="scrollbar-track-vertical" style="position: absolute; width: 6px; display: none;">
                    <div class="scrollbar-thumb-vertical" style="position: relative; display: block; width: 100%;">
                    </div>
                </div>
            </div>
        </div>
        <div class="Resizer resize-horizontal resize-right">
        </div>
    </div>
    <div>
        <div class="h6">Selected groups:</div>
        <ul>
        </ul>
        <div class="h6">Selected vehicles:</div>
        <ul>
        </ul>
        <div class="h6">Expanded groups:</div>
        <ul>
            <li>Mixed Vehicles</li>
        </ul>
    </div>
</div>
```

#### Props: AssetTree

### AssetTree

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| fly | boolean | false | Defines if the component will overlap the body content. |
| resizable | boolean | true | Defines whether or not the sidebar is resizable. |
| bordered | boolean | false | Defines whether the component has a border or not. |
| width | number | 350 | Defines the width of the component. The value is set as inline style. Note: when component is resizable it will take the provided width in px only and convert it to number in case. |
| minWidth | number | 100 | Defines the minimum width of the component in px that will take effect when resizing. |
| maxWidth | number | 0 | Defines the maximum width of the component in px that will take effect when resizing. |
| height | number | — | Defines the height of the component in px. |
| isOpen | boolean | true | Defines whether the component is open or not. |
| onToggleTree | (isOpen: boolean) => void | () => {} | Callback for when the tree visibility is toggled. |
| currentCategoryId | string | — | The id of the category which is currently active and shall be shown. |
| onCategoryChange | (selectedCategoryId: string) => void | () => {} | Callback for handling change of category. |
| onResizeEnd | VoidFunction | () => {} | Callback for when the resize is done. |
| useOffscreen | boolean | false | Defines whether the tree components are rendered offscreen and kept mounted in the DOM. |
| className | string | — | Additional classes added on the wrapper element. |

#### Props: TreeCategory

### TreeCategory

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| id | string | — | A unique identifier for that category. |
| icon | string | — | The rioglyph icon name for that category. |
| label | string \| React.ReactNode | — | The optional label for the category which will be shown in a tooltip. |
| hasSelection | boolean | — | Defines whether or not a selection indicator should be shown. |

#### Props: Tree

### Tree

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| groups | TreeGroup[] | [] | The list of groups of the items. If no groups are provided all items are rendered as flat list. |
| └id | string | — | A unique identifier of a group. |
| └name | string \| React.ReactNode | — | The name of a group. |
| └position | 'last' | — | Can be set to "last" to enforce the last position in the tree. |
| └disabled | boolean | — | Disallows the selection of the group itself. |
| └icon | string | — | The rioglyph icon name for a group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └expandedIcon | string | — | The rioglyph icon name for a expanded group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └className | string | — | Additional classes added to the group element. |
| items | TreeItem[] | [] | The list of items. |
| └id | string | — | A unique identifier of an item. |
| └name | string \| TreeItemName | — | The name of an item. Either it is a plain string or an object composed of: firstName and lastName where lastName is mandatory. |
| └info | string \| React.ReactNode | — | The subline of an item. This can e used to show additional information for that item. |
| └type | string | — | The primary type of the item. This is also used as the fallback icon name and refers to the name of the respective rioglyph icon (excluding the rioglyph- prefix). |
| └icon | string \| null | — | Optional icon override for the item. If set to a string (e.g. 'truck'), this icon will be used explicitly. If set to undefined, the type property will be used as the fallback icon. If set to null, no icon will be rendered, even if type is defined. This allows full control over the icon behavior while maintaining backward compatibility with type-based icons. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └subType | string | — | Optional sub-type of the item. This refers to the name of an additional rioglyph icon (excluding the rioglyph- prefix), typically used to render a secondary icon next to the primary one (Note: for fuel types better use the pairIcon prop). |
| └pairIcon | string \| null \| undefined | — | Optional pair icon override for the subType. If set to a string (e.g. 'fuel-gas'), this icon will be used explicitly. If set to undefined, the subType property will be used as the fallback icon. If set to null, no icon will be rendered, even if subType is defined. This allows full control over the icon behavior while maintaining backward compatibility with subType-based icons. |
| └groupIds | string[] | [] | List of group ids the items is associated with. |
| └className | string | — | Additional classes added to the item element. |
| selectedGroups | string[] | [] | List of selected group ids. |
| selectedItems | string[] | [] | List of selected item ids. |
| onSelectionChange | ({ items, groups }: SelectionChangeResponse) => void | — | Merged Callback for item and group selection changes. It responds with a selection object that contains the selected itemIds and groupIds: { items: [], groups: [] } |
| hasMultiselect | boolean | true | Defines the selection behavior of the tree. |
| showRadioButtons | boolean | false | Defines if the single selection should also show radios. |
| hideSearch | boolean | false | Defines whether or not the built-in Search is shown. |
| searchPlaceholder | string | — | The text used as placeholder for the search input. |
| onSearchChange | (value: string) => void | — | Callback for when the search value changes. |
| search | React.ReactNode | — | Used to define custom search component which replaces the built-in search. |
| summary | React.ReactNode | — | Used to define custom asset type counter component which replaces the built-in summary. |
| hideSummary | boolean | false | Defines whether a summary is shown. |
| onTypeFilterChange | (currentTypes: string[]) => void | — | Callback triggered when the built-in asset type filter changes. This is only available when the default summary is used. |
| hideTreeHead | boolean | false | Defines whether the entire area below the search field is shown or not. Note: Disabling the tree head will hide the select all checkbox and the tree options as well as the tree summary. |
| treeHeaderContent | React.ReactElement | — | Additional custom content that is rendered at the top of the tree component. This can be used for nav pills. |
| scrollHeight | number | — | Defines the max-height of the scrollable list. |
| expandedGroups | string[] | — | List of group ids which are expanded. |
| onExpandGroupsChange | (newExpandedGroups: string[]) => void | — | Callback function triggered when a group expands or collapses. |
| showEmptyGroups | boolean | true | Defines whether empty groups are shown or not. |
| treeOptions | React.ReactNode[] | — | Component to offer customization options for the tree. |
| treeOptionsTooltip | React.ReactNode | — | Tooltip content for the tree options dropdown. |
| disableAnimation | boolean | false | Disables animation when filtering or using search |
| virtualizeThreshold | number | 50 | The number of items (including groups and children) used for virtualizing the tree. |
| overscan | number | 5 | The number of items rendered beyond the visible area of a virtualized tree. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSearch

### TreeSearch

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| value | string | — | The search value to be shown and used for the search. |
| onChange | (newValue: string, event: React.ChangeEvent \| React.MouseEvent) => void | () => {} | Callback for when the search value changes. |
| placeholder | string | — | The placeholder text used for the input field. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSummary

### TreeSummary

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| assetCounts | TreeSummaryCounts | — | The object containing various asset type counter. |
| └truck | number | — | The amount of trucks |
| └trailer | number | — | The amount of trailers |
| └bus | number | — | The amount of buses |
| └van | number | — | The amount of vans |
| └car | number | — | The amount of cars |
| └driver | number | — | The amount of drivers |
| gridCols | number | 4 | The number of grid columns used for the built-in TreeSummaryRow. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSummaryRow

### TreeSummaryRow

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| gridCols | number | 4 | Defined the number of grid columns for a single row. Note, when the amount of children exceed the columns it will wrap around to a new line. |

#### Props: TypeCounter

### TypeCounter

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| type | string | — | The item type for that counter. This will be used as a return value for the onClick callback. |
| icon | string | — | The icon name. Note, when using the built-in generic type counter, the icon name will the same as the item type. So make sure there is a corresponding icon for the defined type. |
| isActive | boolean | — | Sets the active styling if active |
| hasFilter | boolean | false | Should be set when there is a type filter set in the tree to style the counter accordingly. |
| enableActivity | boolean | false | Allows for interactivity. Use this prop when you allow clicking on the counter. |
| hideOnZero | boolean | false | Defines if the counter is rendered at all when the value is not defined ot 0. |
| onClick | (type: string) => void | — | Callback function when the counter is clicked. It returns the type value. Make sure the "type" prop is defined to receive the value in the callback. |
| value | string \| React.ReactNode \| number | — | A custom value to be shown in the counter. |

#### Props: TreeOption

### TreeOption

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| isChecked | boolean | false | Defines whether the option is set. |
| onChange | (event: React.MouseEvent<HTMLDivElement>) => void | — | Callback triggered when option is selected. |
| label | string \| React.ReactNode | — | The label for the option. |
| className | string | — | Additional classes added to the wrapping element. |

## AssetTree with custom summary

### Example: Some small dummy text at the bottom to showcase that you can put something here

3
15

John Doe
Maxl Rainer
Johan Schmidt

Some small dummy text at the bottom to showcase that you can put something here

#### React (tsx)

```tsx
import { useState } from 'react';
import { countBy } from 'es-toolkit/compat';

import AssetTree from '@rio-cloud/rio-uikit/AssetTree';
import TreeCategory from '@rio-cloud/rio-uikit/TreeCategory';
import Tree, { type TreeItemName, type TreeItem } from '@rio-cloud/rio-uikit/Tree';
import TreeSummary from '@rio-cloud/rio-uikit/TreeSummary';
import TypeCounter from '@rio-cloud/rio-uikit/TypeCounter';
import Notification from '@rio-cloud/rio-uikit/Notification';

const CATEGORY_DRIVER = 'assets';

const drivers: TreeItem[] = [
    {
        id: '74e8eb86-18a1-4abe-90cb-aeee7909f857',
        name: {
            firstName: 'John',
            lastName: 'Doe',
        },
        type: 'driver',
    },
    {
        id: '3abc20f5-e0b6-42bb-b310-4e57fdd2be55',
        name: {
            firstName: 'Maxl',
            lastName: 'Rainer',
        },
        type: 'driver',
    },
    {
        id: '3abc20f5-e0b6-42bb-b310-4e57fdd2be56',
        name: {
            firstName: 'Johan',
            lastName: 'Schmidt',
        },
        type: 'driver',
    },
];

const getTypeCounts = (items: TreeItem[]) => countBy(items, item => item.type);

const AssetTreeWithCustomSummaryExample = () => {
    const [counters, setCounters] = useState({
        driver: 3,
        driverOut: 15,
    });

    const handleSearchChange = (searchValue: string) => {
        const filteredDriver = drivers.filter(driver =>
            `${(driver.name as TreeItemName).firstName} ${(driver.name as TreeItemName).lastName}`
                .toLowerCase()
                .includes(searchValue.toLowerCase())
        );
        const counts = getTypeCounts(filteredDriver);

        setCounters({
            ...counters,
            driver: counts.driver,
        });
    };

    return (
        <div className='display-flex flex-wrap overflow-auto'>
            <AssetTree
                resizable
                bordered
                minWidth={300}
                maxWidth={450}
                currentCategoryId={CATEGORY_DRIVER}
                height={500}
                isOpen
            >
                <TreeCategory
                    key={CATEGORY_DRIVER}
                    id={CATEGORY_DRIVER}
                    label='Driver'
                    icon='rioglyph-driver'
                    hasSelection={false}
                >
                    <div className='flex-1-1 display-flex flex-column justify-content-between'>
                        <Tree
                            summary={
                                <TreeSummary>
                                    <TypeCounter
                                        icon='driver'
                                        value={counters.driver}
                                        enableActivity
                                        type='driver'
                                        onClick={(type: string) => Notification.default(`TypeCounter ${type} clicked`)}
                                    />
                                    <TypeCounter icon='drivercard-out' value={counters.driverOut} />
                                </TreeSummary>
                            }
                            groups={[]}
                            items={drivers}
                            expandedGroups={[]}
                            selectedGroups={[]}
                            selectedItems={[]}
                            searchPlaceholder='Find driver by name'
                            onSearchChange={handleSearchChange}
                            hasMultiselect={false}
                        />
                        <div className='margin-15 padding-10 rounded border1 border-color-lightest shadow-accent text-color-dark line-height-125rel'>
                            Some small dummy text at the bottom to showcase that you can put something here
                        </div>
                    </div>
                </TreeCategory>
            </AssetTree>
        </div>
    );
};

export default AssetTreeWithCustomSummaryExample;
```

#### HTML (html)

```html
<div class="display-flex flex-wrap overflow-auto">
    <div class="AssetTree border fluid" style="width: 350px; height: 500px;">
        <div class="AssetTreeResizeLimit" style="left: 450px;">
        </div>
        <div class="AssetTreeContent">
            <div class="TreeSidebar">
                <ul class="TreeSidebarNavigation">
                    <li class="active">
                        <div class="selection-bubble">
                            <span class="rioglyph rioglyph-driver">
                            </span>
                        </div>
                    </li>
                </ul>
                <div class="TreeSidebarToggle">
                    <span class="rioglyph rioglyph-chevron-left">
                    </span>
                </div>
            </div>
            <div class="AssetTreeBody scrollbar-fly-in smooth-scrollbar-wrapper" style="position: relative; overflow: hidden; width: 100%; height: 100%;">
                <div class="scrollbar-view" style="position: absolute; inset: 0px; overflow: scroll; margin-right: 0px; margin-bottom: 0px;">
                    <div class="scrollbar-content-wrapper">
                        <div class="flex-1-1 display-flex flex-column justify-content-between">
                            <div class="Tree">
                                <div class="TreeHeader">
                                    <div class="TreeSearch">
                                        <div class="input-group flex-1-0">
                                            <span class="input-group-addon">
                                                <span class="rioglyph rioglyph-search" aria-hidden="true">
                                                </span>
                                            </span>
                                            <div class="ClearableInput input-group">
                                                <input placeholder="Find driver by name" class="form-control" type="text" tabindex="0" value="">
                                                <span class="clearButton hide">
                                                    <span class="clearButtonIcon rioglyph rioglyph-remove-sign">
                                                    </span>
                                                </span>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="TreeHead display-flex gap-5 padding-15">
                                        <div class="border border-right-only hidden-empty padding-right-10 margin-right-2">
                                        </div>
                                        <div class="display-flex justify-content-between align-items-start width-100pct">
                                            <div class="TreeSummary display-flex flex-wrap align-items-center gap-10 padding-left-3">
                                                <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 cursor-pointer">
                                                    <span class="rioglyph rioglyph-driver text-size-16 margin-right-2">
                                                    </span>
                                                    <span class="TreeLabelCount label label-condensed label-muted label-filled">3</span>
                                                </div>
                                                <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 pointer-events-none">
                                                    <span class="rioglyph rioglyph-drivercard-out text-size-16 margin-right-2">
                                                    </span>
                                                    <span class="TreeLabelCount label label-condensed label-muted label-filled">15</span>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                                <div class="TreeRoot user-select-none overflow-hidden" style="position: relative;">
                                    <div class="TreeNodeContainer user-select-none overflow-hidden open">
                                        <div class="TreeLeaf form-group margin-bottom-0" data-key="74e8eb86-18a1-4abe-90cb-aeee7909f857">
                                            <span class="TreeLabel TreeLabelName">
                                                <span class="rioglyph rioglyph-driver">
                                                </span>
                                                <span class="TreeLabelNameText">
                                                    <span class="TreeLabelNameTextHeadline">
                                                        <span class="text-light margin-right-3">John</span>
                                                        <span>Doe</span>
                                                    </span>
                                                </span>
                                            </span>
                                        </div>
                                        <div class="TreeLeaf form-group margin-bottom-0" data-key="3abc20f5-e0b6-42bb-b310-4e57fdd2be55">
                                            <span class="TreeLabel TreeLabelName">
                                                <span class="rioglyph rioglyph-driver">
                                                </span>
                                                <span class="TreeLabelNameText">
                                                    <span class="TreeLabelNameTextHeadline">
                                                        <span class="text-light margin-right-3">Maxl</span>
                                                        <span>Rainer</span>
                                                    </span>
                                                </span>
                                            </span>
                                        </div>
                                        <div class="TreeLeaf form-group margin-bottom-0" data-key="3abc20f5-e0b6-42bb-b310-4e57fdd2be56">
                                            <span class="TreeLabel TreeLabelName">
                                                <span class="rioglyph rioglyph-driver">
                                                </span>
                                                <span class="TreeLabelNameText">
                                                    <span class="TreeLabelNameTextHeadline">
                                                        <span class="text-light margin-right-3">Johan</span>
                                                        <span>Schmidt</span>
                                                    </span>
                                                </span>
                                            </span>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="margin-15 padding-10 rounded border1 border-color-lightest shadow-accent text-color-dark line-height-125rel">Some small dummy text at the bottom to showcase that you can put something here</div>
                        </div>
                    </div>
                </div>
                <div class="scrollbar-track-horizontal" style="position: absolute; height: 6px; display: none;">
                    <div class="scrollbar-thumb-horizontal" style="position: relative; display: block; height: 100%;">
                    </div>
                </div>
                <div class="scrollbar-track-vertical" style="position: absolute; width: 6px; display: none;">
                    <div class="scrollbar-thumb-vertical" style="position: relative; display: block; width: 100%;">
                    </div>
                </div>
            </div>
        </div>
        <div class="Resizer resize-horizontal resize-right">
        </div>
    </div>
</div>
```

#### Props: AssetTree

### AssetTree

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| fly | boolean | false | Defines if the component will overlap the body content. |
| resizable | boolean | true | Defines whether or not the sidebar is resizable. |
| bordered | boolean | false | Defines whether the component has a border or not. |
| width | number | 350 | Defines the width of the component. The value is set as inline style. Note: when component is resizable it will take the provided width in px only and convert it to number in case. |
| minWidth | number | 100 | Defines the minimum width of the component in px that will take effect when resizing. |
| maxWidth | number | 0 | Defines the maximum width of the component in px that will take effect when resizing. |
| height | number | — | Defines the height of the component in px. |
| isOpen | boolean | true | Defines whether the component is open or not. |
| onToggleTree | (isOpen: boolean) => void | () => {} | Callback for when the tree visibility is toggled. |
| currentCategoryId | string | — | The id of the category which is currently active and shall be shown. |
| onCategoryChange | (selectedCategoryId: string) => void | () => {} | Callback for handling change of category. |
| onResizeEnd | VoidFunction | () => {} | Callback for when the resize is done. |
| useOffscreen | boolean | false | Defines whether the tree components are rendered offscreen and kept mounted in the DOM. |
| className | string | — | Additional classes added on the wrapper element. |

#### Props: TreeCategory

### TreeCategory

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| id | string | — | A unique identifier for that category. |
| icon | string | — | The rioglyph icon name for that category. |
| label | string \| React.ReactNode | — | The optional label for the category which will be shown in a tooltip. |
| hasSelection | boolean | — | Defines whether or not a selection indicator should be shown. |

#### Props: Tree

### Tree

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| groups | TreeGroup[] | [] | The list of groups of the items. If no groups are provided all items are rendered as flat list. |
| └id | string | — | A unique identifier of a group. |
| └name | string \| React.ReactNode | — | The name of a group. |
| └position | 'last' | — | Can be set to "last" to enforce the last position in the tree. |
| └disabled | boolean | — | Disallows the selection of the group itself. |
| └icon | string | — | The rioglyph icon name for a group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └expandedIcon | string | — | The rioglyph icon name for a expanded group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └className | string | — | Additional classes added to the group element. |
| items | TreeItem[] | [] | The list of items. |
| └id | string | — | A unique identifier of an item. |
| └name | string \| TreeItemName | — | The name of an item. Either it is a plain string or an object composed of: firstName and lastName where lastName is mandatory. |
| └info | string \| React.ReactNode | — | The subline of an item. This can e used to show additional information for that item. |
| └type | string | — | The primary type of the item. This is also used as the fallback icon name and refers to the name of the respective rioglyph icon (excluding the rioglyph- prefix). |
| └icon | string \| null | — | Optional icon override for the item. If set to a string (e.g. 'truck'), this icon will be used explicitly. If set to undefined, the type property will be used as the fallback icon. If set to null, no icon will be rendered, even if type is defined. This allows full control over the icon behavior while maintaining backward compatibility with type-based icons. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └subType | string | — | Optional sub-type of the item. This refers to the name of an additional rioglyph icon (excluding the rioglyph- prefix), typically used to render a secondary icon next to the primary one (Note: for fuel types better use the pairIcon prop). |
| └pairIcon | string \| null \| undefined | — | Optional pair icon override for the subType. If set to a string (e.g. 'fuel-gas'), this icon will be used explicitly. If set to undefined, the subType property will be used as the fallback icon. If set to null, no icon will be rendered, even if subType is defined. This allows full control over the icon behavior while maintaining backward compatibility with subType-based icons. |
| └groupIds | string[] | [] | List of group ids the items is associated with. |
| └className | string | — | Additional classes added to the item element. |
| selectedGroups | string[] | [] | List of selected group ids. |
| selectedItems | string[] | [] | List of selected item ids. |
| onSelectionChange | ({ items, groups }: SelectionChangeResponse) => void | — | Merged Callback for item and group selection changes. It responds with a selection object that contains the selected itemIds and groupIds: { items: [], groups: [] } |
| hasMultiselect | boolean | true | Defines the selection behavior of the tree. |
| showRadioButtons | boolean | false | Defines if the single selection should also show radios. |
| hideSearch | boolean | false | Defines whether or not the built-in Search is shown. |
| searchPlaceholder | string | — | The text used as placeholder for the search input. |
| onSearchChange | (value: string) => void | — | Callback for when the search value changes. |
| search | React.ReactNode | — | Used to define custom search component which replaces the built-in search. |
| summary | React.ReactNode | — | Used to define custom asset type counter component which replaces the built-in summary. |
| hideSummary | boolean | false | Defines whether a summary is shown. |
| onTypeFilterChange | (currentTypes: string[]) => void | — | Callback triggered when the built-in asset type filter changes. This is only available when the default summary is used. |
| hideTreeHead | boolean | false | Defines whether the entire area below the search field is shown or not. Note: Disabling the tree head will hide the select all checkbox and the tree options as well as the tree summary. |
| treeHeaderContent | React.ReactElement | — | Additional custom content that is rendered at the top of the tree component. This can be used for nav pills. |
| scrollHeight | number | — | Defines the max-height of the scrollable list. |
| expandedGroups | string[] | — | List of group ids which are expanded. |
| onExpandGroupsChange | (newExpandedGroups: string[]) => void | — | Callback function triggered when a group expands or collapses. |
| showEmptyGroups | boolean | true | Defines whether empty groups are shown or not. |
| treeOptions | React.ReactNode[] | — | Component to offer customization options for the tree. |
| treeOptionsTooltip | React.ReactNode | — | Tooltip content for the tree options dropdown. |
| disableAnimation | boolean | false | Disables animation when filtering or using search |
| virtualizeThreshold | number | 50 | The number of items (including groups and children) used for virtualizing the tree. |
| overscan | number | 5 | The number of items rendered beyond the visible area of a virtualized tree. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSearch

### TreeSearch

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| value | string | — | The search value to be shown and used for the search. |
| onChange | (newValue: string, event: React.ChangeEvent \| React.MouseEvent) => void | () => {} | Callback for when the search value changes. |
| placeholder | string | — | The placeholder text used for the input field. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSummary

### TreeSummary

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| assetCounts | TreeSummaryCounts | — | The object containing various asset type counter. |
| └truck | number | — | The amount of trucks |
| └trailer | number | — | The amount of trailers |
| └bus | number | — | The amount of buses |
| └van | number | — | The amount of vans |
| └car | number | — | The amount of cars |
| └driver | number | — | The amount of drivers |
| gridCols | number | 4 | The number of grid columns used for the built-in TreeSummaryRow. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSummaryRow

### TreeSummaryRow

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| gridCols | number | 4 | Defined the number of grid columns for a single row. Note, when the amount of children exceed the columns it will wrap around to a new line. |

#### Props: TypeCounter

### TypeCounter

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| type | string | — | The item type for that counter. This will be used as a return value for the onClick callback. |
| icon | string | — | The icon name. Note, when using the built-in generic type counter, the icon name will the same as the item type. So make sure there is a corresponding icon for the defined type. |
| isActive | boolean | — | Sets the active styling if active |
| hasFilter | boolean | false | Should be set when there is a type filter set in the tree to style the counter accordingly. |
| enableActivity | boolean | false | Allows for interactivity. Use this prop when you allow clicking on the counter. |
| hideOnZero | boolean | false | Defines if the counter is rendered at all when the value is not defined ot 0. |
| onClick | (type: string) => void | — | Callback function when the counter is clicked. It returns the type value. Make sure the "type" prop is defined to receive the value in the callback. |
| value | string \| React.ReactNode \| number | — | A custom value to be shown in the counter. |

#### Props: TreeOption

### TreeOption

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| isChecked | boolean | false | Defines whether the option is set. |
| onChange | (event: React.MouseEvent<HTMLDivElement>) => void | — | Callback triggered when option is selected. |
| label | string \| React.ReactNode | — | The label for the option. |
| className | string | — | Additional classes added to the wrapping element. |

## Tree with custom icons

### Example: Example 5

Group 01 11

Group 02 3

Group 03 6

#### React (tsx)

```tsx
import { useState } from 'react';
import { random } from 'es-toolkit/compat';
import { faker } from '@faker-js/faker';

import Tree, { type TreeItem, type TreeGroup, type SelectionChangeResponse } from '@rio-cloud/rio-uikit/Tree';

const groups: TreeGroup[] = [
    {
        id: '1',
        name: 'Group 01',
        icon: 'https://cdn.rio.cloud/images/uikit/react_logo.svg',
    },
    {
        id: '2',
        name: 'Group 02',
        icon: 'https://cdn.rio.cloud/images/uikit/react_logo.svg',
    },
    {
        id: '3',
        name: 'Group 03',
        icon: 'https://cdn.rio.cloud/svg/common/ico_rio_colored.svg',
    },
];

const treeItems: TreeItem[] = Array.from({ length: 20 }, (_, index) => ({
    id: `${index}`,
    name: `${faker.lorem.words()} ${random(100, 999)}`,
    type: 'files',
    icon: 'https://cdn.rio.cloud/svg/common/ico_rio_colored.svg',
    groupIds: [faker.helpers.arrayElement(groups).id],
}));

export default () => {
    const [selectedItemIds, setSelectedItemIds] = useState<string[]>([]);
    const [expandedGroups, setExpandedGroups] = useState<string[]>([]);

    const handleSelection = ({ items }: SelectionChangeResponse) => {
        setSelectedItemIds(items);
    };

    const handleExpandGroups = (newExpandedGroups: string[]) => setExpandedGroups(newExpandedGroups);

    return (
        <div className='display-flex flex-wrap gap-25 overflow-auto'>
            <div className='width-500 border border-color-lighter border-bottom-none'>
                <Tree
                    groups={groups}
                    items={treeItems}
                    expandedGroups={expandedGroups}
                    onExpandGroupsChange={handleExpandGroups}
                    selectedItems={selectedItemIds}
                    onSelectionChange={handleSelection}
                    searchPlaceholder='Find items'
                    scrollHeight={300}
                    hasMultiselect={false}
                    hideTreeHead
                />
            </div>
        </div>
    );
};
```

#### HTML (html)

```html
<div class="display-flex flex-wrap gap-25 overflow-auto">
    <div class="width-500 border border-color-lighter border-bottom-none">
        <div class="Tree">
            <div class="TreeHeader">
                <div class="TreeSearch">
                    <div class="input-group flex-1-0">
                        <span class="input-group-addon">
                            <span class="rioglyph rioglyph-search" aria-hidden="true">
                            </span>
                        </span>
                        <div class="ClearableInput input-group">
                            <input placeholder="Find items" class="form-control" type="text" tabindex="0" value="">
                            <span class="clearButton hide">
                                <span class="clearButtonIcon rioglyph rioglyph-remove-sign">
                                </span>
                            </span>
                        </div>
                    </div>
                </div>
            </div>
            <div class="TreeRoot user-select-none overflow-auto" style="max-height: 300px; position: relative;">
                <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="1">
                    <div class="TreeNode from-group" data-key="1">
                        <span class="TreeLabel TreeLabelName">
                            <div class="display-grid place-items-center margin-right-5" style="width: 18px; height: 18px;">
                                <img src="https://cdn.rio.cloud/images/uikit/react_logo.svg" style="max-width: 100%; max-height: 100%;">
                            </div>
                            <span class="TreeLabelNameText">
                                <span class="TreeLabelNameTextHeadline">Group 01</span>
                            </span>
                            <span class="TreeLabelCount label label-muted label-filled label-condensed">11</span>
                            <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                            </span>
                        </span>
                    </div>
                </div>
                <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="2">
                    <div class="TreeNode from-group" data-key="2">
                        <span class="TreeLabel TreeLabelName">
                            <div class="display-grid place-items-center margin-right-5" style="width: 18px; height: 18px;">
                                <img src="https://cdn.rio.cloud/images/uikit/react_logo.svg" style="max-width: 100%; max-height: 100%;">
                            </div>
                            <span class="TreeLabelNameText">
                                <span class="TreeLabelNameTextHeadline">Group 02</span>
                            </span>
                            <span class="TreeLabelCount label label-muted label-filled label-condensed">3</span>
                            <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                            </span>
                        </span>
                    </div>
                </div>
                <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="3">
                    <div class="TreeNode from-group" data-key="3">
                        <span class="TreeLabel TreeLabelName">
                            <div class="display-grid place-items-center margin-right-5" style="width: 18px; height: 18px;">
                                <img src="https://cdn.rio.cloud/svg/common/ico_rio_colored.svg" style="max-width: 100%; max-height: 100%;">
                            </div>
                            <span class="TreeLabelNameText">
                                <span class="TreeLabelNameTextHeadline">Group 03</span>
                            </span>
                            <span class="TreeLabelCount label label-muted label-filled label-condensed">6</span>
                            <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                            </span>
                        </span>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
```

#### Props: AssetTree

### AssetTree

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| fly | boolean | false | Defines if the component will overlap the body content. |
| resizable | boolean | true | Defines whether or not the sidebar is resizable. |
| bordered | boolean | false | Defines whether the component has a border or not. |
| width | number | 350 | Defines the width of the component. The value is set as inline style. Note: when component is resizable it will take the provided width in px only and convert it to number in case. |
| minWidth | number | 100 | Defines the minimum width of the component in px that will take effect when resizing. |
| maxWidth | number | 0 | Defines the maximum width of the component in px that will take effect when resizing. |
| height | number | — | Defines the height of the component in px. |
| isOpen | boolean | true | Defines whether the component is open or not. |
| onToggleTree | (isOpen: boolean) => void | () => {} | Callback for when the tree visibility is toggled. |
| currentCategoryId | string | — | The id of the category which is currently active and shall be shown. |
| onCategoryChange | (selectedCategoryId: string) => void | () => {} | Callback for handling change of category. |
| onResizeEnd | VoidFunction | () => {} | Callback for when the resize is done. |
| useOffscreen | boolean | false | Defines whether the tree components are rendered offscreen and kept mounted in the DOM. |
| className | string | — | Additional classes added on the wrapper element. |

#### Props: TreeCategory

### TreeCategory

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| id | string | — | A unique identifier for that category. |
| icon | string | — | The rioglyph icon name for that category. |
| label | string \| React.ReactNode | — | The optional label for the category which will be shown in a tooltip. |
| hasSelection | boolean | — | Defines whether or not a selection indicator should be shown. |

#### Props: Tree

### Tree

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| groups | TreeGroup[] | [] | The list of groups of the items. If no groups are provided all items are rendered as flat list. |
| └id | string | — | A unique identifier of a group. |
| └name | string \| React.ReactNode | — | The name of a group. |
| └position | 'last' | — | Can be set to "last" to enforce the last position in the tree. |
| └disabled | boolean | — | Disallows the selection of the group itself. |
| └icon | string | — | The rioglyph icon name for a group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └expandedIcon | string | — | The rioglyph icon name for a expanded group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └className | string | — | Additional classes added to the group element. |
| items | TreeItem[] | [] | The list of items. |
| └id | string | — | A unique identifier of an item. |
| └name | string \| TreeItemName | — | The name of an item. Either it is a plain string or an object composed of: firstName and lastName where lastName is mandatory. |
| └info | string \| React.ReactNode | — | The subline of an item. This can e used to show additional information for that item. |
| └type | string | — | The primary type of the item. This is also used as the fallback icon name and refers to the name of the respective rioglyph icon (excluding the rioglyph- prefix). |
| └icon | string \| null | — | Optional icon override for the item. If set to a string (e.g. 'truck'), this icon will be used explicitly. If set to undefined, the type property will be used as the fallback icon. If set to null, no icon will be rendered, even if type is defined. This allows full control over the icon behavior while maintaining backward compatibility with type-based icons. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └subType | string | — | Optional sub-type of the item. This refers to the name of an additional rioglyph icon (excluding the rioglyph- prefix), typically used to render a secondary icon next to the primary one (Note: for fuel types better use the pairIcon prop). |
| └pairIcon | string \| null \| undefined | — | Optional pair icon override for the subType. If set to a string (e.g. 'fuel-gas'), this icon will be used explicitly. If set to undefined, the subType property will be used as the fallback icon. If set to null, no icon will be rendered, even if subType is defined. This allows full control over the icon behavior while maintaining backward compatibility with subType-based icons. |
| └groupIds | string[] | [] | List of group ids the items is associated with. |
| └className | string | — | Additional classes added to the item element. |
| selectedGroups | string[] | [] | List of selected group ids. |
| selectedItems | string[] | [] | List of selected item ids. |
| onSelectionChange | ({ items, groups }: SelectionChangeResponse) => void | — | Merged Callback for item and group selection changes. It responds with a selection object that contains the selected itemIds and groupIds: { items: [], groups: [] } |
| hasMultiselect | boolean | true | Defines the selection behavior of the tree. |
| showRadioButtons | boolean | false | Defines if the single selection should also show radios. |
| hideSearch | boolean | false | Defines whether or not the built-in Search is shown. |
| searchPlaceholder | string | — | The text used as placeholder for the search input. |
| onSearchChange | (value: string) => void | — | Callback for when the search value changes. |
| search | React.ReactNode | — | Used to define custom search component which replaces the built-in search. |
| summary | React.ReactNode | — | Used to define custom asset type counter component which replaces the built-in summary. |
| hideSummary | boolean | false | Defines whether a summary is shown. |
| onTypeFilterChange | (currentTypes: string[]) => void | — | Callback triggered when the built-in asset type filter changes. This is only available when the default summary is used. |
| hideTreeHead | boolean | false | Defines whether the entire area below the search field is shown or not. Note: Disabling the tree head will hide the select all checkbox and the tree options as well as the tree summary. |
| treeHeaderContent | React.ReactElement | — | Additional custom content that is rendered at the top of the tree component. This can be used for nav pills. |
| scrollHeight | number | — | Defines the max-height of the scrollable list. |
| expandedGroups | string[] | — | List of group ids which are expanded. |
| onExpandGroupsChange | (newExpandedGroups: string[]) => void | — | Callback function triggered when a group expands or collapses. |
| showEmptyGroups | boolean | true | Defines whether empty groups are shown or not. |
| treeOptions | React.ReactNode[] | — | Component to offer customization options for the tree. |
| treeOptionsTooltip | React.ReactNode | — | Tooltip content for the tree options dropdown. |
| disableAnimation | boolean | false | Disables animation when filtering or using search |
| virtualizeThreshold | number | 50 | The number of items (including groups and children) used for virtualizing the tree. |
| overscan | number | 5 | The number of items rendered beyond the visible area of a virtualized tree. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSearch

### TreeSearch

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| value | string | — | The search value to be shown and used for the search. |
| onChange | (newValue: string, event: React.ChangeEvent \| React.MouseEvent) => void | () => {} | Callback for when the search value changes. |
| placeholder | string | — | The placeholder text used for the input field. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSummary

### TreeSummary

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| assetCounts | TreeSummaryCounts | — | The object containing various asset type counter. |
| └truck | number | — | The amount of trucks |
| └trailer | number | — | The amount of trailers |
| └bus | number | — | The amount of buses |
| └van | number | — | The amount of vans |
| └car | number | — | The amount of cars |
| └driver | number | — | The amount of drivers |
| gridCols | number | 4 | The number of grid columns used for the built-in TreeSummaryRow. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TreeSummaryRow

### TreeSummaryRow

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| gridCols | number | 4 | Defined the number of grid columns for a single row. Note, when the amount of children exceed the columns it will wrap around to a new line. |

#### Props: TypeCounter

### TypeCounter

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| type | string | — | The item type for that counter. This will be used as a return value for the onClick callback. |
| icon | string | — | The icon name. Note, when using the built-in generic type counter, the icon name will the same as the item type. So make sure there is a corresponding icon for the defined type. |
| isActive | boolean | — | Sets the active styling if active |
| hasFilter | boolean | false | Should be set when there is a type filter set in the tree to style the counter accordingly. |
| enableActivity | boolean | false | Allows for interactivity. Use this prop when you allow clicking on the counter. |
| hideOnZero | boolean | false | Defines if the counter is rendered at all when the value is not defined ot 0. |
| onClick | (type: string) => void | — | Callback function when the counter is clicked. It returns the type value. Make sure the "type" prop is defined to receive the value in the callback. |
| value | string \| React.ReactNode \| number | — | A custom value to be shown in the counter. |

#### Props: TreeOption

### TreeOption

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| isChecked | boolean | false | Defines whether the option is set. |
| onChange | (event: React.MouseEvent<HTMLDivElement>) => void | — | Callback triggered when option is selected. |
| label | string \| React.ReactNode | — | The label for the option. |
| className | string | — | Additional classes added to the wrapping element. |

## Tree

### Example: Tree with header and search

Tree with header and search

20

Folder 01 3

Folder 02 7

Folder 03 7

Folder 04 3

Selected items:

Expanded folders:

#### React (tsx)

```tsx
import { useState } from 'react';
import { random } from 'es-toolkit/compat';
import { faker } from '@faker-js/faker';

import Tree, { type TreeItem, type TreeGroup, type SelectionChangeResponse } from '@rio-cloud/rio-uikit/Tree';
import LabeledElement from '@rio-cloud/rio-uikit/LabeledElement';

const folders: TreeGroup[] = [
    {
        id: '1',
        name: 'Folder 01',
        icon: 'folder-open',
    },
    {
        id: '2',
        name: 'Folder 02',
        icon: 'folder-open',
    },
    {
        id: '3',
        name: 'Folder 03',
        icon: 'folder-open',
    },
    {
        id: '4',
        name: 'Folder 04',
        icon: 'folder-open',
    },
];

const treeItems: TreeItem[] = Array.from({ length: 20 }, (_, index) => ({
    id: `${index}`,
    name: `${faker.lorem.words()} ${random(100, 999)}`,
    type: 'files',
    icon: 'files',
    // icon: null,  // Set to "null" to omit the icon
    groupIds: [faker.helpers.arrayElement(folders).id],
}));

const TreeOnlyExample = () => {
    const [selectedItemIds, setSelectedItemIds] = useState<string[]>([]);
    const [expandedFolders, setExpandedFolders] = useState<string[]>([]);

    const handleSelection = ({ items }: SelectionChangeResponse) => {
        setSelectedItemIds(items);
    };

    const handleExpandFolder = (newExpandedFolders: string[]) => setExpandedFolders(newExpandedFolders);

    const renderSelectedItemsOfList = (itemIds: string[], list: TreeGroup[] | TreeItem[]) =>
        itemIds.map(selectedItemId => {
            const result = list.find(listItem => listItem.id === selectedItemId);
            if (result) {
                return <li key={selectedItemId}>{`${result.name}`}</li>;
            }
            return null;
        });

    return (
        <div className='display-flex flex-wrap gap-25 overflow-auto'>
            <div className='width-500'>
                <LabeledElement label='Tree with header and search'>
                    <Tree
                        groups={folders}
                        items={treeItems}
                        expandedGroups={expandedFolders}
                        onExpandGroupsChange={handleExpandFolder}
                        selectedItems={selectedItemIds}
                        onSelectionChange={handleSelection}
                        searchPlaceholder='Find file'
                        scrollHeight={300}
                        hasMultiselect={false}
                    />
                </LabeledElement>
            </div>
            <div>
                <div className='h6'>Selected items:</div>
                <ul>{renderSelectedItemsOfList(selectedItemIds, treeItems)}</ul>
                <div className='h6'>Expanded folders:</div>
                <ul>{renderSelectedItemsOfList(expandedFolders, folders)}</ul>
            </div>
        </div>
    );
};

export default TreeOnlyExample;
```

#### HTML (html)

```html
<div class="display-flex flex-wrap gap-25 overflow-auto">
    <div class="width-500">
        <div class="LabeledElement display-flex flex-column">
            <div class="text-color-dark max-width-100pct text-size-12 display-inline-block margin-bottom-5">Tree with header and search</div>
            <div class="Tree">
                <div class="TreeHeader">
                    <div class="TreeSearch">
                        <div class="input-group flex-1-0">
                            <span class="input-group-addon">
                                <span class="rioglyph rioglyph-search" aria-hidden="true">
                                </span>
                            </span>
                            <div class="ClearableInput input-group">
                                <input placeholder="Find file" class="form-control" type="text" tabindex="0" value="">
                                <span class="clearButton hide">
                                    <span class="clearButtonIcon rioglyph rioglyph-remove-sign">
                                    </span>
                                </span>
                            </div>
                        </div>
                    </div>
                    <div class="TreeHead display-flex gap-5 padding-15">
                        <div class="border border-right-only hidden-empty padding-right-10 margin-right-2">
                        </div>
                        <div class="display-flex justify-content-between align-items-start width-100pct">
                            <div class="TreeSummary display-flex flex-wrap align-items-center gap-10 padding-left-3">
                                <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 pointer-events-none">
                                    <span class="rioglyph rioglyph-files text-size-16 margin-right-2">
                                    </span>
                                    <span class="TreeLabelCount label label-condensed label-muted label-filled">20</span>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="TreeRoot user-select-none overflow-auto" style="max-height: 300px; position: relative;">
                    <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="1">
                        <div class="TreeNode from-group" data-key="1">
                            <span class="TreeLabel TreeLabelName">
                                <span class="rioglyph rioglyph-folder-open">
                                </span>
                                <span class="TreeLabelNameText">
                                    <span class="TreeLabelNameTextHeadline">Folder 01</span>
                                </span>
                                <span class="TreeLabelCount label label-muted label-filled label-condensed">3</span>
                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                </span>
                            </span>
                        </div>
                    </div>
                    <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="2">
                        <div class="TreeNode from-group" data-key="2">
                            <span class="TreeLabel TreeLabelName">
                                <span class="rioglyph rioglyph-folder-open">
                                </span>
                                <span class="TreeLabelNameText">
                                    <span class="TreeLabelNameTextHeadline">Folder 02</span>
                                </span>
                                <span class="TreeLabelCount label label-muted label-filled label-condensed">7</span>
                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                </span>
                            </span>
                        </div>
                    </div>
                    <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="3">
                        <div class="TreeNode from-group" data-key="3">
                            <span class="TreeLabel TreeLabelName">
                                <span class="rioglyph rioglyph-folder-open">
                                </span>
                                <span class="TreeLabelNameText">
                                    <span class="TreeLabelNameTextHeadline">Folder 03</span>
                                </span>
                                <span class="TreeLabelCount label label-muted label-filled label-condensed">7</span>
                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                </span>
                            </span>
                        </div>
                    </div>
                    <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="4">
                        <div class="TreeNode from-group" data-key="4">
                            <span class="TreeLabel TreeLabelName">
                                <span class="rioglyph rioglyph-folder-open">
                                </span>
                                <span class="TreeLabelNameText">
                                    <span class="TreeLabelNameTextHeadline">Folder 04</span>
                                </span>
                                <span class="TreeLabelCount label label-muted label-filled label-condensed">3</span>
                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                </span>
                            </span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div>
        <div class="h6">Selected items:</div>
        <ul>
        </ul>
        <div class="h6">Expanded folders:</div>
        <ul>
        </ul>
    </div>
</div>
```

#### Props: Tree

### Tree

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| groups | TreeGroup[] | [] | The list of groups of the items. If no groups are provided all items are rendered as flat list. |
| └id | string | — | A unique identifier of a group. |
| └name | string \| React.ReactNode | — | The name of a group. |
| └position | 'last' | — | Can be set to "last" to enforce the last position in the tree. |
| └disabled | boolean | — | Disallows the selection of the group itself. |
| └icon | string | — | The rioglyph icon name for a group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └expandedIcon | string | — | The rioglyph icon name for a expanded group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └className | string | — | Additional classes added to the group element. |
| items | TreeItem[] | [] | The list of items. |
| └id | string | — | A unique identifier of an item. |
| └name | string \| TreeItemName | — | The name of an item. Either it is a plain string or an object composed of: firstName and lastName where lastName is mandatory. |
| └info | string \| React.ReactNode | — | The subline of an item. This can e used to show additional information for that item. |
| └type | string | — | The primary type of the item. This is also used as the fallback icon name and refers to the name of the respective rioglyph icon (excluding the rioglyph- prefix). |
| └icon | string \| null | — | Optional icon override for the item. If set to a string (e.g. 'truck'), this icon will be used explicitly. If set to undefined, the type property will be used as the fallback icon. If set to null, no icon will be rendered, even if type is defined. This allows full control over the icon behavior while maintaining backward compatibility with type-based icons. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └subType | string | — | Optional sub-type of the item. This refers to the name of an additional rioglyph icon (excluding the rioglyph- prefix), typically used to render a secondary icon next to the primary one (Note: for fuel types better use the pairIcon prop). |
| └pairIcon | string \| null \| undefined | — | Optional pair icon override for the subType. If set to a string (e.g. 'fuel-gas'), this icon will be used explicitly. If set to undefined, the subType property will be used as the fallback icon. If set to null, no icon will be rendered, even if subType is defined. This allows full control over the icon behavior while maintaining backward compatibility with subType-based icons. |
| └groupIds | string[] | [] | List of group ids the items is associated with. |
| └className | string | — | Additional classes added to the item element. |
| selectedGroups | string[] | [] | List of selected group ids. |
| selectedItems | string[] | [] | List of selected item ids. |
| onSelectionChange | ({ items, groups }: SelectionChangeResponse) => void | — | Merged Callback for item and group selection changes. It responds with a selection object that contains the selected itemIds and groupIds: { items: [], groups: [] } |
| hasMultiselect | boolean | true | Defines the selection behavior of the tree. |
| showRadioButtons | boolean | false | Defines if the single selection should also show radios. |
| hideSearch | boolean | false | Defines whether or not the built-in Search is shown. |
| searchPlaceholder | string | — | The text used as placeholder for the search input. |
| onSearchChange | (value: string) => void | — | Callback for when the search value changes. |
| search | React.ReactNode | — | Used to define custom search component which replaces the built-in search. |
| summary | React.ReactNode | — | Used to define custom asset type counter component which replaces the built-in summary. |
| hideSummary | boolean | false | Defines whether a summary is shown. |
| onTypeFilterChange | (currentTypes: string[]) => void | — | Callback triggered when the built-in asset type filter changes. This is only available when the default summary is used. |
| hideTreeHead | boolean | false | Defines whether the entire area below the search field is shown or not. Note: Disabling the tree head will hide the select all checkbox and the tree options as well as the tree summary. |
| treeHeaderContent | React.ReactElement | — | Additional custom content that is rendered at the top of the tree component. This can be used for nav pills. |
| scrollHeight | number | — | Defines the max-height of the scrollable list. |
| expandedGroups | string[] | — | List of group ids which are expanded. |
| onExpandGroupsChange | (newExpandedGroups: string[]) => void | — | Callback function triggered when a group expands or collapses. |
| showEmptyGroups | boolean | true | Defines whether empty groups are shown or not. |
| treeOptions | React.ReactNode[] | — | Component to offer customization options for the tree. |
| treeOptionsTooltip | React.ReactNode | — | Tooltip content for the tree options dropdown. |
| disableAnimation | boolean | false | Disables animation when filtering or using search |
| virtualizeThreshold | number | 50 | The number of items (including groups and children) used for virtualizing the tree. |
| overscan | number | 5 | The number of items rendered beyond the visible area of a virtualized tree. |
| className | string | — | Additional classes added to the wrapping element. |

### Example: Tree without header and search

Tree without header and search

Folder 01 6

Folder 02 7

Folder 03 3

Folder 04 4

Selected items:

Expanded folders:

#### React (tsx)

```tsx
import { useState } from 'react';
import { random } from 'es-toolkit/compat';
import { faker } from '@faker-js/faker';

import Tree, { type TreeItem, type TreeGroup, type SelectionChangeResponse } from '@rio-cloud/rio-uikit/Tree';
import LabeledElement from '@rio-cloud/rio-uikit/LabeledElement';

const folders2: TreeGroup[] = [
    {
        id: '1',
        name: 'Folder 01',
        icon: 'folder-closed',
        expandedIcon: 'folder-open',
    },
    {
        id: '2',
        name: 'Folder 02',
        icon: 'folder-closed',
        expandedIcon: 'folder-open',
    },
    {
        id: '3',
        name: 'Folder 03',
        icon: 'folder-closed',
        expandedIcon: 'folder-open',
    },
    {
        id: '4',
        name: 'Folder 04',
        icon: 'folder-closed',
        expandedIcon: 'folder-open',
    },
];

const treeItems2: TreeItem[] = Array.from({ length: 20 }, (_, index) => ({
    id: `${index}`,
    name: `${faker.lorem.words()} ${random(100, 999)}`,
    type: 'files',
    icon: null, // Set to "null" to omit the icon
    groupIds: [faker.helpers.arrayElement(folders2).id],
}));

const TreeOnlyExample = () => {
    const [selectedItemIds, setSelectedItemIds] = useState<string[]>([]);
    const [expandedFolders, setExpandedFolders] = useState<string[]>([]);

    const handleSelection = ({ items }: SelectionChangeResponse) => {
        setSelectedItemIds(items);
    };

    const handleExpandFolder = (newExpandedFolders: string[]) => setExpandedFolders(newExpandedFolders);

    const renderSelectedItemsOfList = (itemIds: string[], list: TreeGroup[] | TreeItem[]) =>
        itemIds.map(selectedItemId => {
            const result = list.find(listItem => listItem.id === selectedItemId);
            if (result) {
                return <li key={selectedItemId}>{`${result.name}`}</li>;
            }
            return null;
        });

    return (
        <div className='display-flex flex-wrap gap-25 overflow-auto'>
            <div className='width-500'>
                <LabeledElement label='Tree without header and search'>
                    <Tree
                        groups={folders2}
                        items={treeItems2}
                        expandedGroups={expandedFolders}
                        onExpandGroupsChange={handleExpandFolder}
                        selectedItems={selectedItemIds}
                        onSelectionChange={handleSelection}
                        scrollHeight={300}
                        hasMultiselect={false}
                        hideSearch={true}
                        hideTreeHead={true}
                    />
                </LabeledElement>
            </div>
            <div>
                <div className='h6'>Selected items:</div>
                <ul>{renderSelectedItemsOfList(selectedItemIds, treeItems2)}</ul>
                <div className='h6'>Expanded folders:</div>
                <ul>{renderSelectedItemsOfList(expandedFolders, folders2)}</ul>
            </div>
        </div>
    );
};

export default TreeOnlyExample;
```

#### HTML (html)

```html
<div class="display-flex flex-wrap gap-25 overflow-auto">
    <div class="width-500">
        <div class="LabeledElement display-flex flex-column">
            <div class="text-color-dark max-width-100pct text-size-12 display-inline-block margin-bottom-5">Tree without header and search</div>
            <div class="Tree">
                <div class="TreeHeader">
                </div>
                <div class="TreeRoot user-select-none overflow-auto" style="max-height: 300px; position: relative;">
                    <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="1">
                        <div class="TreeNode from-group" data-key="1">
                            <span class="TreeLabel TreeLabelName">
                                <span class="rioglyph rioglyph-folder-closed">
                                </span>
                                <span class="TreeLabelNameText">
                                    <span class="TreeLabelNameTextHeadline">Folder 01</span>
                                </span>
                                <span class="TreeLabelCount label label-muted label-filled label-condensed">6</span>
                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                </span>
                            </span>
                        </div>
                    </div>
                    <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="2">
                        <div class="TreeNode from-group" data-key="2">
                            <span class="TreeLabel TreeLabelName">
                                <span class="rioglyph rioglyph-folder-closed">
                                </span>
                                <span class="TreeLabelNameText">
                                    <span class="TreeLabelNameTextHeadline">Folder 02</span>
                                </span>
                                <span class="TreeLabelCount label label-muted label-filled label-condensed">7</span>
                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                </span>
                            </span>
                        </div>
                    </div>
                    <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="3">
                        <div class="TreeNode from-group" data-key="3">
                            <span class="TreeLabel TreeLabelName">
                                <span class="rioglyph rioglyph-folder-closed">
                                </span>
                                <span class="TreeLabelNameText">
                                    <span class="TreeLabelNameTextHeadline">Folder 03</span>
                                </span>
                                <span class="TreeLabelCount label label-muted label-filled label-condensed">3</span>
                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                </span>
                            </span>
                        </div>
                    </div>
                    <div class="TreeNodeContainer user-select-none overflow-hidden" data-id="4">
                        <div class="TreeNode from-group" data-key="4">
                            <span class="TreeLabel TreeLabelName">
                                <span class="rioglyph rioglyph-folder-closed">
                                </span>
                                <span class="TreeLabelNameText">
                                    <span class="TreeLabelNameTextHeadline">Folder 04</span>
                                </span>
                                <span class="TreeLabelCount label label-muted label-filled label-condensed">4</span>
                                <span class="TreeLabelExpander rioglyph rioglyph-chevron-down ">
                                </span>
                            </span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div>
        <div class="h6">Selected items:</div>
        <ul>
        </ul>
        <div class="h6">Expanded folders:</div>
        <ul>
        </ul>
    </div>
</div>
```

#### Props: Tree

### Tree

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| groups | TreeGroup[] | [] | The list of groups of the items. If no groups are provided all items are rendered as flat list. |
| └id | string | — | A unique identifier of a group. |
| └name | string \| React.ReactNode | — | The name of a group. |
| └position | 'last' | — | Can be set to "last" to enforce the last position in the tree. |
| └disabled | boolean | — | Disallows the selection of the group itself. |
| └icon | string | — | The rioglyph icon name for a group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └expandedIcon | string | — | The rioglyph icon name for a expanded group. The prefix rioglyph- can be omitted. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └className | string | — | Additional classes added to the group element. |
| items | TreeItem[] | [] | The list of items. |
| └id | string | — | A unique identifier of an item. |
| └name | string \| TreeItemName | — | The name of an item. Either it is a plain string or an object composed of: firstName and lastName where lastName is mandatory. |
| └info | string \| React.ReactNode | — | The subline of an item. This can e used to show additional information for that item. |
| └type | string | — | The primary type of the item. This is also used as the fallback icon name and refers to the name of the respective rioglyph icon (excluding the rioglyph- prefix). |
| └icon | string \| null | — | Optional icon override for the item. If set to a string (e.g. 'truck'), this icon will be used explicitly. If set to undefined, the type property will be used as the fallback icon. If set to null, no icon will be rendered, even if type is defined. This allows full control over the icon behavior while maintaining backward compatibility with type-based icons. For custom icons and logos, provide an image URL with one of these extensions: .png, .webp, .jpg, .jpeg, .svg. In this case, an img tag is rendered instead of the rioglyph. |
| └subType | string | — | Optional sub-type of the item. This refers to the name of an additional rioglyph icon (excluding the rioglyph- prefix), typically used to render a secondary icon next to the primary one (Note: for fuel types better use the pairIcon prop). |
| └pairIcon | string \| null \| undefined | — | Optional pair icon override for the subType. If set to a string (e.g. 'fuel-gas'), this icon will be used explicitly. If set to undefined, the subType property will be used as the fallback icon. If set to null, no icon will be rendered, even if subType is defined. This allows full control over the icon behavior while maintaining backward compatibility with subType-based icons. |
| └groupIds | string[] | [] | List of group ids the items is associated with. |
| └className | string | — | Additional classes added to the item element. |
| selectedGroups | string[] | [] | List of selected group ids. |
| selectedItems | string[] | [] | List of selected item ids. |
| onSelectionChange | ({ items, groups }: SelectionChangeResponse) => void | — | Merged Callback for item and group selection changes. It responds with a selection object that contains the selected itemIds and groupIds: { items: [], groups: [] } |
| hasMultiselect | boolean | true | Defines the selection behavior of the tree. |
| showRadioButtons | boolean | false | Defines if the single selection should also show radios. |
| hideSearch | boolean | false | Defines whether or not the built-in Search is shown. |
| searchPlaceholder | string | — | The text used as placeholder for the search input. |
| onSearchChange | (value: string) => void | — | Callback for when the search value changes. |
| search | React.ReactNode | — | Used to define custom search component which replaces the built-in search. |
| summary | React.ReactNode | — | Used to define custom asset type counter component which replaces the built-in summary. |
| hideSummary | boolean | false | Defines whether a summary is shown. |
| onTypeFilterChange | (currentTypes: string[]) => void | — | Callback triggered when the built-in asset type filter changes. This is only available when the default summary is used. |
| hideTreeHead | boolean | false | Defines whether the entire area below the search field is shown or not. Note: Disabling the tree head will hide the select all checkbox and the tree options as well as the tree summary. |
| treeHeaderContent | React.ReactElement | — | Additional custom content that is rendered at the top of the tree component. This can be used for nav pills. |
| scrollHeight | number | — | Defines the max-height of the scrollable list. |
| expandedGroups | string[] | — | List of group ids which are expanded. |
| onExpandGroupsChange | (newExpandedGroups: string[]) => void | — | Callback function triggered when a group expands or collapses. |
| showEmptyGroups | boolean | true | Defines whether empty groups are shown or not. |
| treeOptions | React.ReactNode[] | — | Component to offer customization options for the tree. |
| treeOptionsTooltip | React.ReactNode | — | Tooltip content for the tree options dropdown. |
| disableAnimation | boolean | false | Disables animation when filtering or using search |
| virtualizeThreshold | number | 50 | The number of items (including groups and children) used for virtualizing the tree. |
| overscan | number | 5 | The number of items rendered beyond the visible area of a virtualized tree. |
| className | string | — | Additional classes added to the wrapping element. |

## TreeSummary with assetCounts

### Example: Example 8

12
7
2
2
10

#### React (tsx)

```tsx
import TreeSummary from '@rio-cloud/rio-uikit/TreeSummary';

const assetCounts = {
    truck: 12,
    trailer: 7,
    bus: 2,
    van: 2,
    driver: 10,
};

const TreeSummaryExample = () => <TreeSummary assetCounts={assetCounts} gridCols={5} />;

export default TreeSummaryExample;
```

#### HTML (html)

```html
<div class="TreeSummary display-flex flex-wrap align-items-center gap-10 padding-left-3">
    <div class="TreeSummaryRow display-grid grid-cols-5 gap-10">
        <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 pointer-events-none">
            <span class="rioglyph rioglyph-truck-baseline text-size-16 margin-right-2">
            </span>
            <span class="TreeLabelCount label label-condensed label-muted label-filled">12</span>
        </div>
        <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 pointer-events-none">
            <span class="rioglyph rioglyph-trailer-baseline text-size-16 margin-right-2">
            </span>
            <span class="TreeLabelCount label label-condensed label-muted label-filled">7</span>
        </div>
        <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 pointer-events-none">
            <span class="rioglyph rioglyph-bus-baseline text-size-16 margin-right-2">
            </span>
            <span class="TreeLabelCount label label-condensed label-muted label-filled">2</span>
        </div>
        <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 pointer-events-none">
            <span class="rioglyph rioglyph-van-baseline text-size-16 margin-right-2">
            </span>
            <span class="TreeLabelCount label label-condensed label-muted label-filled">2</span>
        </div>
        <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 pointer-events-none">
            <span class="rioglyph rioglyph-driver text-size-16 margin-right-2">
            </span>
            <span class="TreeLabelCount label label-condensed label-muted label-filled">10</span>
        </div>
    </div>
</div>
```

#### Props: TreeSummary

### TreeSummary

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| assetCounts | TreeSummaryCounts | — | The object containing various asset type counter. |
| └truck | number | — | The amount of trucks |
| └trailer | number | — | The amount of trailers |
| └bus | number | — | The amount of buses |
| └van | number | — | The amount of vans |
| └car | number | — | The amount of cars |
| └driver | number | — | The amount of drivers |
| gridCols | number | 4 | The number of grid columns used for the built-in TreeSummaryRow. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TypeCounter

### TypeCounter

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| type | string | — | The item type for that counter. This will be used as a return value for the onClick callback. |
| icon | string | — | The icon name. Note, when using the built-in generic type counter, the icon name will the same as the item type. So make sure there is a corresponding icon for the defined type. |
| isActive | boolean | — | Sets the active styling if active |
| hasFilter | boolean | false | Should be set when there is a type filter set in the tree to style the counter accordingly. |
| enableActivity | boolean | false | Allows for interactivity. Use this prop when you allow clicking on the counter. |
| hideOnZero | boolean | false | Defines if the counter is rendered at all when the value is not defined ot 0. |
| onClick | (type: string) => void | — | Callback function when the counter is clicked. It returns the type value. Make sure the "type" prop is defined to receive the value in the callback. |
| value | string \| React.ReactNode \| number | — | A custom value to be shown in the counter. |

## TreeSummary with TypeCounter

### Example: Example 9

9
15

#### React (tsx)

```tsx
import TreeSummary from '@rio-cloud/rio-uikit/TreeSummary';
import TypeCounter from '@rio-cloud/rio-uikit/TypeCounter';

const TreeSummaryCustomExample = () => (
    <TreeSummary>
        <TypeCounter icon='driver' value={9} />
        <TypeCounter icon='drivercard-out' value={15} />
    </TreeSummary>
);

export default TreeSummaryCustomExample;
```

#### HTML (html)

```html
<div class="TreeSummary display-flex flex-wrap align-items-center gap-10 padding-left-3">
    <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 pointer-events-none">
        <span class="rioglyph rioglyph-driver text-size-16 margin-right-2">
        </span>
        <span class="TreeLabelCount label label-condensed label-muted label-filled">9</span>
    </div>
    <div class="TypeCounter display-flex align-items-center user-select-none margin-right-2 pointer-events-none">
        <span class="rioglyph rioglyph-drivercard-out text-size-16 margin-right-2">
        </span>
        <span class="TreeLabelCount label label-condensed label-muted label-filled">15</span>
    </div>
</div>
```

#### Props: TreeSummary

### TreeSummary

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| assetCounts | TreeSummaryCounts | — | The object containing various asset type counter. |
| └truck | number | — | The amount of trucks |
| └trailer | number | — | The amount of trailers |
| └bus | number | — | The amount of buses |
| └van | number | — | The amount of vans |
| └car | number | — | The amount of cars |
| └driver | number | — | The amount of drivers |
| gridCols | number | 4 | The number of grid columns used for the built-in TreeSummaryRow. |
| className | string | — | Additional classes added to the wrapping element. |

#### Props: TypeCounter

### TypeCounter

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| type | string | — | The item type for that counter. This will be used as a return value for the onClick callback. |
| icon | string | — | The icon name. Note, when using the built-in generic type counter, the icon name will the same as the item type. So make sure there is a corresponding icon for the defined type. |
| isActive | boolean | — | Sets the active styling if active |
| hasFilter | boolean | false | Should be set when there is a type filter set in the tree to style the counter accordingly. |
| enableActivity | boolean | false | Allows for interactivity. Use this prop when you allow clicking on the counter. |
| hideOnZero | boolean | false | Defines if the counter is rendered at all when the value is not defined ot 0. |
| onClick | (type: string) => void | — | Callback function when the counter is clicked. It returns the type value. Make sure the "type" prop is defined to receive the value in the callback. |
| value | string \| React.ReactNode \| number | — | A custom value to be shown in the counter. |