Can you believe that the treeview on the image below does not use any JavaScript, but relies only on CSS3?
Today I’m going to show you a really easy and absolutely JavaScript-less solution for creating multi-level treeviews with minimal markup and with the power of CSS3. Basically what we need is a simple list:
<div class="css-treeview"> <ul></ul> </div>
… With any number of nested items and subtrees. Each item that is going to be a container of a subtree should be supplied with a label and a checkbox.
Normal (non-clickable) item:
<li><a href="./">item</a></li> <li><a href="./">item</a></li>
Expandable (clickable) submenu item:
<li><input type="checkbox" id="item-0" /><label for="item-0">folder</label> <ul> <li><input type="checkbox" id="item-0-0" /><label for="item-0-0">folder</label> <ul> <li><input type="checkbox" id="item-0-0-0" /><label for="item-0-0-0">folder</label> <ul> <li><a href="./">item</a></li> <li><a href="./">item</a></li> <li><a href="./">item</a></li> <li><a href="./">item</a></li> </ul> </li> </ul> </li> </ul> </li>
Making it work is pretty simple and straightforward. All we need is to query the normal and :checked states of the checkboxes and set the adjacent <ul /> element to visible or hidden in the stylesheet:
Unchecked checkbox:
.css-treeview input + label + ul
{
display: none;
}
Selected checkbox:
.css-treeview input:checked + label + ul
{
display: block;
}
<pre>
For aesthetic purposes we hide the checkboxes like this:
.css-treeview input
{
position: absolute;
opacity: 0;
}
It is recommended to hide the checkbox with position/opacity rather than with display: none, otherwise you will have problems with certain browsers.
If your treeview is going to contain disabled subtrees, you can utilize the :not() selector, so disabled items with submenus will not be clickable:
.css-treeview input:checked:not(:disabled) + label + ul
{
display: block;
}
The visual representation of the disabled items can be accomplished by changing the opacity and the cursor of the label element:
.css-treeview input:disabled + label
{
cursor: default; /* or no-drop */
opacity: .6;
}
Finally, for the +/- buttons on the left, we can use generated content with the :before pseudo element:
.css-treeview label,
.css-treeview label::before
{
background: url("icons.png") no-repeat;
}
.css-treeview label::before
{
content: "";
width: 16px;
margin: 0 22px 0 0;
vertical-align: middle;
background-position: 0 -32px;
}
.css-treeview input:checked + label::before
{
background-position: 0 -16px;
}
All of the icons that have been used in the example are in the icons.png sprite. The solution will work with any browser supporting the adjacent element selector (E + E) and the attribute selectors of CSS3. Do not forget that the values of the for/id attribute pairs for the label and checkbox elements should be unique, otherwise the treeview will not work. Tab/Spacebar navigation is supported natively. The demo is availble on this page, or you can download it straight away from this link.
Of course this is just the basic concept that you can use for inspiration. A few ideas that can bring you even further:
- By adding the disabled attribute to a checkbox in your markup, the nested subtree will become expanded by default.
- You can use the cool CSS3 transitions to achieve cool behaviors.
- You can use additional classes to display different “folder” items.
- You can use :hover in order to show the pluses and minuse only when the treeview is hovered.
- You can use an additional class name that will show the pluses and minuses only when applied.
- You can use the attribute selectors to display different icons for each normal item according to the extension in the href attribute, for example:
li a[href$=".js"]
{
background: url("js.png") no-repeat center;
}
li a[href$=".css"]
{
background: url("css.png") no-repeat center;
}
View the demo or download it here. Find more experiments here.
Related Posts
- Amazing Ribbonbar Web UI Component
- HTML5 Resume Generator and Onepager Website
- CSS3 Driven Slides Viewer Without any JavaScript
- Fully Functional CSS3-only Tabstrip Without JavaScript
- Selecting only the first element occurence out of siblings with the same class name with CSS3
- Imageless CSS3 Custom Checkboxes and Radio Buttons
- Creating Gaussian Blur Effect With CSS3
- Fancy CSS3 Tooltip (Yeah, Without JavaScript)
- How to Style Select Boxes with CSS3
- CSS3 Element Reflections
- CSS3 iPhone Toggle Buttons
- CSS3 Background Image Cropping

nicing :)
thanks :)
Amazing!
[...] CSS3 can do some amazing things (e.g. http://acidmartin.wordpress.com/2011/09/26/css3-treevew-no-javascript/) [...]
[...] Martin Ivanov demonstrates, using HTML checkboxes and the CSS :checked pseudo-class, how to make an expandable tree view without JavaScript [...]
Works with Google Chrome v18 but not with v19(current) or v20(beta) – the branches do not expand/collapse when clicked with these chrome versions on Windows 7/Server 2008 R2. Google Chrome auto-updated a day or two ago to v19.0.1084.46 and since then it has no longer worked. Safari and iOS confirmed working OK.
Thanks for reporting this, Richard. Will check what the problem may be.
Hey Richard, once again – thank you very much for pointing out this issue. It is now fixed and the updated code is available for download.
Yep, used the “~ ul” trick in my css as per your latest download and now works perfect with Chrome v19. Thanks for updating so quickly!
You are welcome, Richard. Actually I should have used the general sibling selector from the beginning, it’s more flexible and allows markup changes.
…just as a side note, you mention using CSS3 transitions. The most obvious application for this would be to smoothly transition when branches are expanded/collapsed. I’m not sure how this can be achieved when switching between display: none and display: block in CSS as changing the display element seems to break transitions. Any ideas?
You can try to do some opacity transition, combined with position absolute in the initial state, when opacity is 0.
very helpful for maybe api docs.. thanks!
Thanks, Christoph! I am glad you like my work!
How would you modify this if you wanted to display folders as either open/closed based on the state of the checkbox?
Never mind, I think I found the right selector to get the effect I wanted…
.css-treeview input:checked ~ label
{
background-position: 18px -46px; /* in my case I added a fourth icon that is the open folder to the icons.png */
}
Hi Keith, sorry for the late reply. I am glad you figured it out. That’s the selector.
Hi there, I was wondering if it is possible to add an animation effect to this treeview? If its possible then that’ll be awesome!!
Yes, I am sure that some cool CSS3 animations or transitions can be added.
[...] CSS3 Treevew. No JavaScript. [...]
[...] CSS3 Treevew. No JavaScript. [...]
[...] CSS3 Treevew. No JavaScript. [...]
[...] CSS3 Treevew. No JavaScript. [...]
[...] CSS3 Treevew. No JavaScript. [...]
[...] CSS3 Treevew. No JavaScript. [...]
[...] CSS3 Treevew. No JavaScript. [...]
[...] CSS3 Treevew. No JavaScript. [...]
[...] CSS3 Treeview. No JavaScript. [...]
[...] CSS3 Treeview. No JavaScript. [...]
[...] CSS3 Treeview. No JavaScript. [...]
[...] CSS3 Treeview. No JavaScript. [...]
[...] CSS3 Treeview. No JavaScript. [...]
[...] CSS3 Treeview. No JavaScript. [...]
Is it possible to change the icon from a folder to something else like an arrow?
Janis, you can use any design for the folder, you just need to modify the icons sprite.
[...] CSS3 Treeview. No JavaScript. [...]
[...] CSS3 Treeview. No JavaScript. [...]
Tree is fine but it is not connected, i mean lines are not there to show that nodes are at same level, can anyone plz tell me how to update this tree to make it connected.
Well, connecting the items can be quite easy by editing the plus/minus sprite and adding special styles to nested items.
It’s very fine but i want an item expendable and hyper-linked, it’s possible ?
Thanks, Gatien. I guess you can achieve what you need by playing with the markup and the CSS.
I try but the css is not really my forte. If I succeed I’ll post the changes here.
I’m nauseous, so long to find the solution when it is so simple: (
To do this you need to change HTML
# This is Closed By Default Folder
To do this:
# This is Closed By Default Folder and a Hyperlink folder
And change the CSS
# .treeview css-input + label + ul
{
margin: 0 0 0 22px;
}
To do this:
#. treeview css-input + label + ul, .treeview css-input + label + a + ul
{
margin: 0 0 0 22px;
}
Damn my HTML code was executed!
I love this!!! It doesn’t work in IE. I’m building a tool for my team and need browser compatibility if possible. Any ideas?
I am glad you like it. It works with IE9+. Older versions are do not work, because they do no not support sibling selectors, but you can create a fallback with JavaScript.
IE9 is enough for me. I never use IE I just wanted to be able to accommodate people that do! Thanks!
[...] CSS3 Treeview. No JavaScript. [...]
[...] CSS3 Treeview. No JavaScript. [...]
[...] CSS3 Treeview. No JavaScript. [...]
Thank for this nice treeview. It is not working with IE10 and Standard or Quirks Document mode. Can you help me there.
Thanks for the comment. However, I just checked, ane it is working perfectly in IE10 standards compliance mode. I did not check in quirks mode, because I am not interested non-standards compliant mode.
Is that possible to have collapse all and expand all buttons on top and implement the same like you did for single expand. I could not find any in the internet. Do you have any idea??
I found the answer for my problem… I use disabled and checked properties from input tag and it worked.