
Security News
PHP Foundation Says Chainguard Broke Security Embargo Ahead of Emergency Patches
The PHP Foundation says Chainguard broke a security embargo ahead of critical RCE patches, as leaks disrupted the coordinated release.
@pierre/trees
Advanced tools
Path-first file tree UI for the web.
@pierre/trees ships one implementation through four public entry points:
@pierre/trees — vanilla model, mounting API, prepared input helpers, icons,
theming, and core types@pierre/trees/react — React hooks and <FileTree model={...} />@pierre/trees/ssr — preload helpers for declarative-shadow-DOM SSR@pierre/trees/web-components — custom-element registration side effectThe tree renders inside a shadow root and keeps public state keyed by canonical path strings, not internal numeric IDs.
pnpm add @pierre/trees
import { FileTree } from '@pierre/trees';
const mount = document.getElementById('mount')!;
mount.style.height = '320px';
const tree = new FileTree({
flattenEmptyDirectories: true,
initialExpansion: 'open',
paths: ['README.md', 'src/index.ts', 'src/components/Button.tsx'],
search: true,
});
tree.render({ containerWrapper: mount });
Common model methods include:
tree.add(path), tree.move(fromPath, toPath), tree.remove(path), and
tree.resetPaths(paths)tree.openSearch(), tree.setSearch(value), and tree.closeSearch()tree.setGitStatus(entries) and tree.setIcons(config)tree.getItem(path), tree.getSelectedPaths(), tree.getFocusedPath(), and
tree.scrollToPath(path, { focus: false })tree.cleanUp()Prepare large or frequently reloaded path lists once, then pass the prepared
result to FileTree.
import { FileTree, preparePresortedFileTreeInput } from '@pierre/trees';
const paths = ['src/', 'src/index.ts', 'README.md'];
const preparedInput = preparePresortedFileTreeInput(paths);
const tree = new FileTree({ preparedInput });
Use prepareFileTreeInput(paths) for raw input. Use
preparePresortedFileTreeInput(paths) when the final order is already known.
'use client';
import { FileTree, useFileTree } from '@pierre/trees/react';
export function Example({ paths }: { paths: string[] }) {
const { model } = useFileTree({
initialExpansion: 'open',
paths,
search: true,
});
return (
<FileTree
model={model}
header={<strong>Project files</strong>}
renderContextMenu={(item) => <div>Menu for {item.path}</div>}
style={{ height: '320px' }}
/>
);
}
@pierre/trees/react exports FileTree, useFileTree, useFileTreeSearch,
useFileTreeSelection, and useFileTreeSelector.
import { preloadFileTree } from '@pierre/trees/ssr';
import { FileTree, useFileTree } from '@pierre/trees/react';
const preloadedData = preloadFileTree({
id: 'docs-tree',
initialExpansion: 'open',
paths: ['README.md', 'src/index.ts'],
initialVisibleRowCount: 8,
});
export function HydratedTree() {
const { model } = useFileTree({
id: 'docs-tree',
initialExpansion: 'open',
paths: ['README.md', 'src/index.ts'],
initialVisibleRowCount: 8,
});
return (
<FileTree
model={model}
preloadedData={preloadedData}
style={{ height: '240px' }}
/>
);
}
preloadFileTree() returns FileTreeSsrPayload:
{
id: string;
outerStart: string;
domOuterStart: string;
shadowHtml: string;
outerEnd: string;
}
Use ${payload.outerStart}${payload.shadowHtml}${payload.outerEnd} when the
HTML parser will see the markup directly, such as a full server-rendered HTML
response. Use ${payload.domOuterStart}${payload.shadowHtml}${payload.outerEnd}
when inserting the full container string through DOM APIs like innerHTML or
dangerouslySetInnerHTML. Pass { id, shadowHtml } to the React component as
preloadedData.
The host element and shadow root read CSS variables such as:
--trees-selected-bg-override--trees-border-color-override--trees-fg-override--trees-theme-*Translate a Shiki or VS Code theme into tree CSS with themeToTreeStyles():
import { themeToTreeStyles } from '@pierre/trees';
const styles = themeToTreeStyles(theme);
If CSS variables are not enough, unsafeCSS injects raw CSS into the tree
shadow root:
const tree = new FileTree({
paths,
unsafeCSS: `
button[data-type='item'][data-item-selected] {
border-radius: 999px;
}
`,
});
Treat unsafeCSS as an escape hatch. Start with host styles, CSS variables, and
themeToTreeStyles() first.
Import the web-components entry point only when you need the custom element registration side effect:
import '@pierre/trees/web-components';
The root package exports icon, git-status, context-menu, drag/drop, mutation, and row-decoration types. Public callbacks report canonical paths.
const tree = new FileTree({
composition: {
contextMenu: {
enabled: true,
},
},
paths,
});
When the context menu is enabled without an explicit triggerMode, it defaults
to 'right-click'. Set triggerMode to 'button' or 'both' for the
dedicated right-side action lane. In button-capable modes, buttonVisibility
defaults to 'when-needed'; set it to 'always' to show decorative per-row
affordances while the tree still uses one floating trigger button and one
slotted menu surface.
renderRowDecoration owns a flexible row lane. Built-in git status uses the
next fixed lane, so custom decoration content, git status, and the context-menu
affordance can appear on the same row.
From anywhere in the repo:
moonx trees:test
moonx trees:test-e2e
moonx trees:benchmark
moonx trees:benchmark-file-tree-get-item
moonx trees:profile-file-tree
moonx trees:typecheck
moonx trees:build
FAQs
Unknown package
The npm package @pierre/trees receives a total of 0 weekly downloads. As such, @pierre/trees popularity was classified as not popular.
We found that @pierre/trees demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 6 open source maintainers collaborating on the project.

Security News
The PHP Foundation says Chainguard broke a security embargo ahead of critical RCE patches, as leaks disrupted the coordinated release.

Security News
PHP releases emergency patches for two critical RCE vulnerabilities as agencies urge organizations to take unpatched sites offline.

Threat Research
/Security News
A supply chain attack compromised LiteLLM 1.107.0 on PyPI and Docker, spreading malware that steals cloud credentials, developer secrets, and AI provider keys.