Changelog
Source:NEWS.md
shinyTree 1.0.0
CRAN release: 2026-10-28
Fixes from a review of the whole package
-
input$treenow holds the tree as soon as it loads, and is updated when the server sends a new tree withrenderTree()orupdateTree(): it used to stayNULLuntil the user clicked, and kept a replaced tree – and its selection of nodes that no longer exist – until then. A tree is reported once, and only if it differs from whatinput$treeholds, so an observer ofinput$treethat sends the tree back still does not loop (#36). - A tree re-rendered after an error in its render function – a
req()orvalidate()that fails and then passes – no longer stops updatinginput$tree. jsTree’s teardown removed the input binding’s event handlers. - Trees whose id contains
.(or another character with a meaning in CSS selectors) now work. Their options, checkboxes and search were ignored andinput$treewas never set, and withtypesthe page threw an error that stopped every tree on it from reporting. -
updateTree(),expandTree()andcollapseTree()on a tree that has not been shown yet – in a tab not yet opened – are applied once it is, rather than throwing an error in the browser. - Deleting the last node with the context menu now clears
input$tree; it kept the deleted nodes. - A node attribute such as
sttype_labelorsticonColoris no longer taken forsttypeorsticon: attributes were matched by prefix. The same applied to thetext,name,iconandstatefields intreeToJSON(). - Numbers in node data are sent at full precision; they were rounded to four digits, so a numeric id such as
123456.789came back changed. -
sttype,sticonandsttooltipgiven as a number, a factor (from a data frame column, say),NAor more than one value no longer stop the tree from rendering. -
sticonvalues in current Font Awesome form –"fa-solid fa-folder","fas fa-file","fa-file fa-lg"– other icon sets, and image file names without a path are now used as given. Only a bare name such as"file"is expanded, to"fa fa-file". - R’s own attributes on a node – a data frame’s
classandrow.names, say – are no longer sent as node data. - A node without a name is now an error naming the problem, rather than a node labelled
{}. - JSON from
jsonlite::toJSON()can be passed torenderTree()andupdateTree(); it reached the browser already parsed and failed there. -
renderTreeAsync()is now built onrenderTree(): it repopulates a tree in a modal that is reopened (#79), works withbindCache(), and an error in a rejected promise is shown in place of the tree. -
options(shinyTree.defaultParser = "tree")set before the package is loaded, e.g. in.Rprofile, is no longer overwritten, and the package can be loaded again in the same session, asdevtools::load_all()does. The"tree"parser warns about siblings with the same name, which a data.tree cannot keep apart. -
treeToJSON()keeps thecheckedstate, and gives an empty tree rather than one blank node for a root without children. -
dfToTree()builds a tree whose branches end at different depths, as a folder listing gives, where it stopped with an error; it gives an empty list for a data frame with no rows, and names anyhierarchycolumn the data frame lacks.treeToDf()handles an empty tree and empty branches. -
shinyTree()acceptssearch = NULLandanimation = NULL, writes ids into its scripts safely, and puts the search script after the search box rather than inside it. Search also reacts to pasting, not only typing. - Examples
16-async,20-apiand23-file-iconswork again,21-optionshas been rewritten to show what the options do since #36 and can be started withrunApp(), and14-fileslists every file. - Documentation: every exported function documents what it returns; new sections and examples for
renderTree(),updateTree(),renderTreeAsync(),get_checked(),dfToTree()andtreeToDf();format = "classid", theshinyTree.defaultParseroption, the contextmenu turning checkboxes off and thesticonforms are documented; and theontologyToTree()example runs on the bundled ontology. - Requires R >= 3.3.0 and shiny >= 1.6.0, which the package already needed. stringr, htmlwidgets and methods are no longer used, and the unused copies of jQuery and require.js are no longer bundled.
- Tests: an example app that fails to start, or a browser test app that errors, now fails the tests instead of skipping them; every example is started and checked; and fixed waits are replaced by waiting for what the test expects.
New features and other fixes
- New
ontologyToTree()reads an ontology from an OBO (.obo) or OWL (.owl, RDF/XML) file and returns whatrenderTree(lazy = TRUE)needs, so even a large ontology such as the Gene Ontology’s 48,000 terms is shown a level at a time. The hierarchy isis_a; a term with several parents appears under each; obsolete terms are greyed out under anobsoletenode; each node shows its id and definition on hover; search finds terms by name or id anywhere in the ontology. New example28-ontologybrowses the ontology from the issue, or an uploaded file (#33). - A lazy tree that is rebuilt now reports the new tree to the server, so
input$treeno longer keeps the old tree’s selection. - New
renderTree(lazy = TRUE)loads a tree’s nodes from the server as they are opened, for trees too large to send whole. The render expression returnsfunction(path)(orfunction(path, node), to tell same-named siblings apart by theirst*attributes) giving a node’s children; children withstchildren = TRUEare fetched when opened. WithshinyTree(search = TRUE)the whole tree is searched on the server, by walking it or with asearchfunction, and the branches leading to the matches are fetched and opened.state = TRUEreopens remembered branches after a reload. Branches needed at once are fetched in a single request. Requests are checked: only branches the server has sent can be asked for, with the server’s own node data, and errors followshiny.sanitize.errors.updateTree()andexpandTree()stop with an error on a lazy tree. See the new27-lazyexample (#11). - Unticking a child of a ticked parent with
tie_selection = FALSEandstate = TRUEis now remembered: the state was saved before the parent was unticked, so a reload ticked everything again. -
renderTree()given a function now stops with a pointer tolazy = TRUE, rather than leaving the tree empty with a JSON error in the browser. - A tree now repopulates when its element is removed from the page and added back – inside a
modalDialogthat is dismissed and reopened, for example. Contents are pushed to the client rather than returned as an output value, so Shiny had nothing to replay and would not re-run the render function. The client now reports binding an empty tree and the contents are resent (#79). - Fixed
typesbeing ignored for trees nested more than one Shiny module deep. Only the first hyphen of the output id was replaced when looking up the types spec on the client, so the lookup missed and the tree failed to render (#129). - Search now hides non-matching nodes with the
protontheme. jsTree marked them correctly but proton’s stylesheet omits the rule that hides them, which the other themes ship, so every node stayed on screen. shinyTree now declares it in its own stylesheet (#113). - New
stcssclassnode attribute gives a node one or more CSS classes, so an app’s own CSS can style it.stclass, despite its name, has only ever been data and is unchanged (#58). - Node data that R refuses as an attribute – a
classfield holding a list, as trees built from XML often have – no longer stopsinput$treefrom being read. It comes back under anstprefix, e.g.stclass(#58). - New
shinyTree(state = TRUE)remembers which nodes were open, selected and checked in the browser, and restores them when the page is reloaded. Each tree is stored under its own key ("shinyTree-<id>"by default, or pass a string). Nodes are matched by their path from the root, and only the first tree after a reload is restored. When the remembered state disagrees with thestopened/stselected/stcheckedattributes the tree was rendered with, the remembered state wins;state_priority = "code"keeps the app’s instead (#19). - A tree is no longer sent to the browser twice on page load when its render takes more than about 100ms. The check that repopulates a tree whose element is added back (#79) also fired for brand-new trees, so the server resent the tree and jsTree rebuilt it. It now only fires for a tree that was already sent.
- New
sttooltipnode attribute: text shown when the pointer rests on a node’s label.?renderTreenow documents all of thest*node attributes (#66). - Fixed two broken stylesheet links to the Font Awesome CDN on every page with a tree, which each failed with a 403 in the browser console. Font Awesome itself was unaffected and still loads with its integrity hash.
- A tree now works in R Markdown documents with
runtime: shiny. Its scripts and stylesheets were written into the page’s<head>, which R Markdown drops, so jsTree never loaded and the tree stayed empty. They are now declared as HTML dependencies, which also means each is included once per page however many trees it has (#18). - New
expandTree()andcollapseTree()open or close every node of a tree from the server, for “Expand all” / “Collapse all” buttons. The tree is not resent, so selection, checkboxes and search are kept, andinput$treereports the new open state (#42). -
get_selected()andget_checked()gainleaves_only. Withleaves_only = TRUEthey return only nodes that have no children, however deep each branch goes, so selected parents – and, withthree_state, the parents jsTree checks automatically – are left out (#98). - Large trees are much faster to render and to read back. Building a tree’s JSON grew the node list one element at a time and serialised it node by node, and reading
input$treewithget_selected()/get_checked()did the same with the matches, so both were quadratic in the size of the tree. For a 30,000-node tree, rendering went from 14s to 2s andget_checked()from 15s to under 1s. The JSON sent to the browser and the values returned are unchanged (#83). -
renderTree()can now be wrapped inshiny::bindCache(). It was refused outright, and since a tree is sent as a message rather than returned as the output value, caching that value would have left the tree empty on every cache hit. The tree’s JSON is cached instead and sent again on a hit. A tree that is removed from the page and added back (#79) now gets the tree last sent rather than a fresh evaluation of the render expression, matching how Shiny replays other outputs (#109). - Shiny no longer warns about a shared input/output id for every tree. A shinyTree is an input and an output under the same id by design, so the browser console warning – and, with
shiny::devmode(), the on-page error panel – was a false alarm in every app. A shared id that involves anything other than a tree is still reported (#110). - The
04-selectedexample now showsget_selected()andget_checked()side by side, with toggles forcheckbox,tie_selection,whole_nodeandthree_stateand an explanation of how each combination behaves.24-checkbox-optionsshows both too, and?shinyTreedocuments the difference between checked and selected nodes (#136). - With
tie_selection = FALSE,input$treenow reflectsthree_statecascades. It was read before jsTree applied the cascade, so checking a parent reported only the parent rather than its children too, and unchecking a child left its parent reported as checked. - Fixed
get_checked()returning nothing whencheckbox = TRUEandtie_selection = FALSE(#121). - Fixed
get_checked()returning nothing for ticked boxes under the defaulttie_selection = TRUE. jsTree treats checked and selected as the same thing in that mode, so a selected node is now reported as checked, matching jsTree’s ownis_checked()/get_checked()(#121). -
updateTree()no longer reports its own refresh back to the server. Calling it from an observer watchinginput$treecould otherwise loop indefinitely whenoptions(shinyTree.refresh)oroptions(shinyTree.setState)was enabled. Refreshes from other sources are still reported, and the two options are now documented (#36). - Node attribute values are no longer trimmed on their way back to R, so padded keys and fixed-width codes stored in
st*attributes survive a round trip. Node names are still trimmed, which is deliberate (#3). - Fixed
get_selected()/get_checked()returning nothing for trees rendered fromtreeToJSON(). A node state without acheckedkey made the input handler fail with “argument is of length zero”, soinput$treewas never populated (#103). - Fixed duplicate-named sibling nodes collapsing into a single entry, so
get_selected()/get_checked()now report the correct node and its own attributes rather than only the last sibling (#104).
shinyTree 0.3.0
- New function
set_node_attrs()to set distinct node or leaf attributes (useful for creating file tree icons). - New functions
dfToTree()andtreeToDf()convert between a data frame and a tree.
shinyTree 0.2.7
CRAN release: 2019-05-27
- Added context menu support.
- Added support for promises/future to render a tree asynchronously.
- Added additional examples for file browser and metadata retrieval.
- Added support to display various icons using types and specifying tree items
- Added support for conversion from/to data.tree
shinyTree 0.2.6
CRAN release: 2018-10-05
- Many improvements to expose more jsTree options.
- Tree can now be correctly updated (see new examples).
shinyTree 0.2.0
- BREAKING CHANGE: Model the
input$list-style lists after the list structure provided torenderTree, meaning that they are now a simple list with the samest- prefixed attributes. Seeinst/examples/05-structure. - BREAKING CHANGE: removed
selectedattribute fromshinyTree()in favor ofget_selected(). Seeinst/examples/04-selected/.