Treeview
Treeview Layout
<!-- Treeview container -->
<div class="treeview">
<!-- Treeview item -->
<div class="treeview-item">
<!-- Item root element -->
<div class="treeview-item-root">
<!-- Item toggle (to open children on click) -->
<div class="treeview-toggle"></div>
<!-- Item content -->
<div class="treeview-item-content">
<!-- Item checkbox (optional) -->
<label class="checkbox">...</label>
<!-- Item icon (optional) -->
<i class="icon f7-icons">folder_fill</i>
<!-- Item label -->
<div class="treeview-item-label">Item 1</div>
</div>
</div>
<!-- Item children -->
<div class="treeview-item-children">
<!-- Children item. It has same recursive layout -->
<div class="treeview-item">
<div class="treeview-item-root">
...
</div>
<div class="treeview-item-children">
...
</div>
</div>
<!-- Another children item -->
<div class="treeview-item">...</div>
</div>
</div>
<!-- Another item -->
<div class="treeview-item">...</div>
<!-- Item without children -->
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<div class="treeview-item-label">Item 3</div>
</div>
</div>
</div>
</div>
Treeview Item Link
If we need some treeview item to be just a link, we just need to use <a>
tag for treeview-item-root element:
<div class="treeview">
...
<div class="treeview-item">
<a href="/about/" class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">link</i>
<div class="treeview-item-label">About</div>
</div>
</a>
</div>
...
</div>
Treeview Item Toggle
Instead of toggle (or in addition) button, we can make whole treeview item work like a toggle. In this case we need to add treeview-item-toggle
to treeview item root element:
<div class="treeview">
...
<div class="treeview-item">
<!-- additional "treeview-item-toggle" class -->
<div class="treeview-item-root treeview-item-toggle">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<i class="icon f7-icons">folder_fill</i>
<div class="treeview-item-label">images</div>
</div>
</div>
<div class="treeview-item-children">
...
</div>
</div>
...
</div>
Treeview Selectable Item
We can also make treeview item selectable. In this case we need to add treeview-item-selectable
to treeview item root element, and treeview-item-selected
to selected item root element:
<div class="treeview">
...
<div class="treeview-item">
<!-- additional "treeview-item-selectable" class -->
<div class="treeview-item-root treeview-item-selectable">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<i class="icon f7-icons">folder_fill</i>
<div class="treeview-item-label">images</div>
</div>
</div>
<div class="treeview-item-children">
...
</div>
</div>
<div class="treeview-item">
<!-- additional "treeview-item-selected" class on selected item -->
<div class="treeview-item-root treeview-item-selectable treeview-item-selected">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<i class="icon f7-icons">folder_fill</i>
<div class="treeview-item-label">documents</div>
</div>
</div>
<div class="treeview-item-children">
...
</div>
</div>
...
</div>
Treeview App Methods
Let's look at related App methods to work with Treeview:
app.treeview.open(el)- open (expand) Treeview item
- el - HTMLElement or string (with CSS Selector). Treeview item element to open.
app.treeview.close(el)- close (collapse) Treeview item
- el - HTMLElement or string (with CSS Selector). Treeview item element to close.
app.treeview.toggle(el)- toggle (open or close) Treeview item
- el - HTMLElement or string (with CSS Selector). Treeview item element to toggle.
Treeview Events
Treeview will fire the following DOM events on treeview item element and events on app instance:
DOM Events
Event | Target | Description |
---|---|---|
treeview:open | Treeview Item Element<div class="treeview-item"> | Event will be triggered on Treeview item open |
treeview:close | Treeview Item Element<div class="treeview-item"> | Event will be triggered on Treeview item close |
treeview:loadchildren | Treeview Item Element<div class="treeview-item"> | Event will be triggered on first open of Treeview item with |
App Events
Treeview also emits events on app instance.
Event | Target | Description | |
---|---|---|---|
treeviewOpen | (itemEl) | app | Event will be triggered on Treeview item open |
treeviewClose | (itemEl) | app | Event will be triggered on Treeview item close |
treeviewLoadChildren | (itemEl, done) | app | Event will be triggered on first open of Treeview item with treeview-load-children class. As second argument it has function to hide loading preloader. |
Load Children
It is also possible to load children on treeview item open. To make it work, we, at first, need to add treeview-load-children
class to such treeview item. And then listen for treeview:loadchildren
event to proceed with loading. Check the examples below for implementation example.
<div class="treeview">
<div class="treeview-item treeview-load-children">
...
<div class="treeview-item-children">
...
</div>
</div>
</div>
<script>
$('.treeview-load-children').on('treeview:loadchildren', (e) => {
loadChildren: function (e) {
const done = e.detail;
fetch('some-url')
.then(() => {
// ... update UI and call done
done();
})
.catch((err) => {
// in case of error, call done(true) to cancel loading effect
done(true);
})
},
})
//- or
app.on('treeviewLoadChildren', (itemEl, done) => {
loadChildren: function (e) {
fetch('some-url')
.then(() => {
// ... update UI and call done
done();
})
.catch((err) => {
// in case of error, call done(true) to cancel loading effect
done(true);
})
},
})
</script>
CSS Variables
Below is the list of related CSS variables (CSS custom properties).
Note that commented variables are not specified by default and their values is what they fallback to in this case.
:root {
--f7-treeview-item-height: 34px;
--f7-treeview-item-padding-left: 16px;
--f7-treeview-item-padding-right: 16px;
--f7-treeview-toggle-size: 24px;
--f7-treeview-children-offset: 29px;
--f7-treeview-label-font-weight: 400;
--f7-treeview-label-text-color: inherit;
--f7-treeview-icon-size: 24px;
/*
--f7-treeview-selectable-selected-bg-color: rgba(var(--f7-theme-color-rgb), 0.2);
*/
--f7-treeview-toggle-color: rgba(0, 0, 0, 0.5);
--f7-treeview-toggle-hover-bg-color: rgba(0, 0, 0, 0.1);
--f7-treeview-toggle-pressed-bg-color: rgba(0, 0, 0, 0.15);
--f7-treeview-icon-color: rgba(0, 0, 0, 0.5);
--f7-treeview-selectable-hover-bg-color: rgba(0, 0, 0, 0.1);
--f7-treeview-link-hover-bg-color: rgba(0, 0, 0, 0.1);
--f7-treeview-link-pressed-bg-color: rgba(0, 0, 0, 0.15);
}
:root .dark,
:root.dark {
--f7-treeview-toggle-color: rgba(255, 255, 255, 0.5);
--f7-treeview-toggle-hover-bg-color: rgba(255, 255, 255, 0.03);
--f7-treeview-toggle-pressed-bg-color: rgba(255, 255, 255, 0.1);
--f7-treeview-icon-color: rgba(255, 255, 255, 0.75);
--f7-treeview-selectable-hover-bg-color: rgba(255, 255, 255, 0.03);
--f7-treeview-link-hover-bg-color: rgba(255, 255, 255, 0.03);
--f7-treeview-link-pressed-bg-color: rgba(255, 255, 255, 0.11);
}
.ios {
--f7-treeview-label-font-size: 17px;
}
.md {
--f7-treeview-label-font-size: 16px;
}
Examples
<template>
<div class="page">
<div class="navbar">
<div class="navbar-bg"></div>
<div class="navbar-inner sliding">
<div class="title">Treeview</div>
</div>
</div>
<div class="page-content">
<div class="block-title">Basic tree view</div>
<div class="block block-strong block-outline-ios no-padding-horizontal">
<div class="treeview">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<div class="treeview-item-label">Item 1</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<div class="treeview-item-label">Sub Item 1</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<div class="treeview-item-label">Sub Sub Item 1</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<div class="treeview-item-label">Sub Sub Item 2</div>
</div>
</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<div class="treeview-item-label">Sub Item 2</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<div class="treeview-item-label">Sub Sub Item 1</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<div class="treeview-item-label">Sub Sub Item 2</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<div class="treeview-item-label">Item 2</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<div class="treeview-item-label">Sub Item 1</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<div class="treeview-item-label">Sub Sub Item 1</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<div class="treeview-item-label">Sub Sub Item 2</div>
</div>
</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<div class="treeview-item-label">Sub Item 2</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<div class="treeview-item-label">Sub Sub Item 1</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<div class="treeview-item-label">Sub Sub Item 2</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<div class="treeview-item-label">Item 3</div>
</div>
</div>
</div>
</div>
</div>
<div class="block-title">With icons</div>
<div class="block block-strong block-outline-ios no-padding-horizontal">
<div class="treeview">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<i class="icon f7-icons">folder_fill</i>
<div class="treeview-item-label">images</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">photo_fill</i>
<div class="treeview-item-label">avatar.png</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">photo_fill</i>
<div class="treeview-item-label">background.jpg</div>
</div>
</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<i class="icon f7-icons">folder_fill</i>
<div class="treeview-item-label">documents</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">doc_text_fill</i>
<div class="treeview-item-label">cv.docx</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">doc_text_fill</i>
<div class="treeview-item-label">info.docx</div>
</div>
</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">logo_github</i>
<div class="treeview-item-label">.gitignore</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">doc_text_fill</i>
<div class="treeview-item-label">index.html</div>
</div>
</div>
</div>
</div>
</div>
<div class="block-title">With checkboxes</div>
<div class="block block-strong block-outline-ios no-padding-horizontal">
<div class="treeview">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<label class="checkbox">
<input type="checkbox" />
<i class="icon-checkbox"></i>
</label>
<i class="icon f7-icons">folder_fill</i>
<div class="treeview-item-label">images</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<label class="checkbox">
<input type="checkbox" />
<i class="icon-checkbox"></i>
</label>
<i class="icon f7-icons">photo_fill</i>
<div class="treeview-item-label">avatar.png</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<label class="checkbox">
<input type="checkbox" />
<i class="icon-checkbox"></i>
</label>
<i class="icon f7-icons">photo_fill</i>
<div class="treeview-item-label">background.jpg</div>
</div>
</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<label class="checkbox">
<input type="checkbox" />
<i class="icon-checkbox"></i>
</label>
<i class="icon f7-icons">folder_fill</i>
<div class="treeview-item-label">documents</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<label class="checkbox">
<input type="checkbox" />
<i class="icon-checkbox"></i>
</label>
<i class="icon f7-icons">doc_text_fill</i>
<div class="treeview-item-label">cv.docx</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<label class="checkbox">
<input type="checkbox" />
<i class="icon-checkbox"></i>
</label>
<i class="icon f7-icons">doc_text_fill</i>
<div class="treeview-item-label">info.docx</div>
</div>
</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<label class="checkbox">
<input type="checkbox" />
<i class="icon-checkbox"></i>
</label>
<i class="icon f7-icons">logo_github</i>
<div class="treeview-item-label">.gitignore</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<label class="checkbox">
<input type="checkbox" />
<i class="icon-checkbox"></i>
</label>
<i class="icon f7-icons">doc_text_fill</i>
<div class="treeview-item-label">index.html</div>
</div>
</div>
</div>
</div>
</div>
<div class="block-title">Whole item as toggle</div>
<div class="block block-strong block-outline-ios no-padding-horizontal">
<div class="treeview">
<div class="treeview-item treeview-item-toggle">
<div class="treeview-item-root">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<i class="icon f7-icons">folder_fill</i>
<div class="treeview-item-label">images</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">photo_fill</i>
<div class="treeview-item-label">avatar.png</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">photo_fill</i>
<div class="treeview-item-label">background.jpg</div>
</div>
</div>
</div>
</div>
</div>
<div class="treeview-item treeview-item-toggle">
<div class="treeview-item-root">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<i class="icon f7-icons">folder_fill</i>
<div class="treeview-item-label">documents</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">doc_text_fill</i>
<div class="treeview-item-label">cv.docx</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">doc_text_fill</i>
<div class="treeview-item-label">info.docx</div>
</div>
</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">logo_github</i>
<div class="treeview-item-label">.gitignore</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">doc_text_fill</i>
<div class="treeview-item-label">index.html</div>
</div>
</div>
</div>
</div>
</div>
<div class="block-title">Selectable</div>
<div class="block block-strong block-outline-ios no-padding-horizontal">
<div class="treeview">
<div class="treeview-item">
<div class="treeview-item-root treeview-item-selectable" @click=${toggleSelectable}>
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<i class="icon f7-icons">folder_fill</i>
<div class="treeview-item-label">images</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root treeview-item-selectable" @click=${toggleSelectable}>
<div class="treeview-item-content">
<i class="icon f7-icons">photo_fill</i>
<div class="treeview-item-label">avatar.png</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root treeview-item-selectable" @click=${toggleSelectable}>
<div class="treeview-item-content">
<i class="icon f7-icons">photo_fill</i>
<div class="treeview-item-label">background.jpg</div>
</div>
</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root treeview-item-selectable" @click=${toggleSelectable}>
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<i class="icon f7-icons">folder_fill</i>
<div class="treeview-item-label">documents</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<div class="treeview-item-root treeview-item-selectable" @click=${toggleSelectable}>
<div class="treeview-item-content">
<i class="icon f7-icons">doc_text_fill</i>
<div class="treeview-item-label">cv.docx</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root treeview-item-selectable" @click=${toggleSelectable}>
<div class="treeview-item-content">
<i class="icon f7-icons">doc_text_fill</i>
<div class="treeview-item-label">info.docx</div>
</div>
</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root treeview-item-selectable" @click=${toggleSelectable}>
<div class="treeview-item-content">
<i class="icon f7-icons">logo_github</i>
<div class="treeview-item-label">.gitignore</div>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root treeview-item-selectable" @click=${toggleSelectable}>
<div class="treeview-item-content">
<i class="icon f7-icons">doc_text_fill</i>
<div class="treeview-item-label">index.html</div>
</div>
</div>
</div>
</div>
</div>
<div class="block-title">Preload children</div>
<div class="block block-strong block-outline-ios no-padding-horizontal">
<div class="treeview">
<div class="treeview-item treeview-load-children" @treeview:loadchildren=${loadChildren}>
<div class="treeview-item-root">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<i class="icon f7-icons">person_2_fill</i>
<div class="treeview-item-label">Users</div>
</div>
</div>
<div class="treeview-item-children">
${loadedChildren.map((item) => $h`
<div class="treeview-item">
<div class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">person_fill</i>
<div class="treeview-item-label">${item.name}</div>
</div>
</div>
</div>
`)}
</div>
</div>
</div>
</div>
<div class="block-title">With links</div>
<div class="block block-strong block-outline-ios no-padding-horizontal">
<div class="treeview">
<div class="treeview-item">
<div class="treeview-item-root treeview-item-toggle">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<i class="icon f7-icons">square_grid_2x2_fill</i>
<div class="treeview-item-label">Modals</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<a href="/popup/" class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">link</i>
<div class="treeview-item-label">Popup</div>
</div>
</a>
</div>
<div class="treeview-item">
<a href="/dialog/" class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">link</i>
<div class="treeview-item-label">Dialog</div>
</div>
</a>
</div>
<div class="treeview-item">
<a href="/action-sheet/" class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">link</i>
<div class="treeview-item-label">Action Sheet</div>
</div>
</a>
</div>
</div>
</div>
<div class="treeview-item">
<div class="treeview-item-root treeview-item-toggle">
<div class="treeview-toggle"></div>
<div class="treeview-item-content">
<i class="icon f7-icons">square_grid_2x2_fill</i>
<div class="treeview-item-label">Navigation Bars</div>
</div>
</div>
<div class="treeview-item-children">
<div class="treeview-item">
<a href="/navbar/" class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">link</i>
<div class="treeview-item-label">Navbar</div>
</div>
</a>
</div>
<div class="treeview-item">
<a href="/toolbar-tabbar/" class="treeview-item-root">
<div class="treeview-item-content">
<i class="icon f7-icons">link</i>
<div class="treeview-item-label">Toolbar & Tabbar</div>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default (props, { $f7, $el, $, $on, $update }) => {
let loadedChildren = [];
const toggleSelectable = (e) => {
var $targetEl = $(e.target);
if ($targetEl.closest('.treeview-item-selected').length) return;
if ($targetEl.is('.treeview-toggle')) return;
$targetEl.parents('.treeview').find('.treeview-item-selected').removeClass('treeview-item-selected')
$targetEl.closest('.treeview-item-selectable').addClass('treeview-item-selected')
}
const loadChildren = (e) => {
var done = e.detail;
setTimeout(function () {
// call done() to hide preloader
done();
loadedChildren = [
{
name: 'John Doe',
},
{
name: 'Jane Doe',
},
{
name: 'Calvin Johnson',
},
];
$update();
}, 2000);
}
$on('pageInit', () => {
$($el.value).find('input[type="checkbox"]').on('change', function (e) {
var $rootEl = $(e.target).closest('.treeview-item-root');
var $itemEl = $rootEl.parent('.treeview-item');
var $childrenCheckboxes = $itemEl.find('.treeview-item-children input[type="checkbox"]');
var $parentItemEl = $itemEl.parents('.treeview-item');
var $parentCheckbox = $parentItemEl.children('.treeview-item-root').find('input[type="checkbox"]');
if ($childrenCheckboxes.length) {
$childrenCheckboxes.prop('checked', e.target.checked);
}
if ($parentItemEl) {
var checkedChildren = $parentItemEl.find('.treeview-item-children input[type="checkbox"]:checked').length;
$parentCheckbox.prop('checked', checkedChildren > 0);
$parentCheckbox.prop('indeterminate', checkedChildren === 1);
}
})
});
return $render;
};
</script>