Build powerful decision trees with a visual node-based editor
🌐 Website • 🎮 Playground • Features • Installation • Quick Start • Examples
Treege is a modern React library for creating and rendering interactive decision trees. Built on top of ReactFlow, it provides a complete solution for building complex form flows, decision logic, and conditional workflows with an intuitive visual editor.
- Node-based Interface: Drag-and-drop editor powered by ReactFlow
- 4 Node Types: Flow, Group, Input, and UI nodes
- Conditional Edges: Advanced logic with AND/OR operators (
===,!==,>,<,>=,<=) - Multi-language Support: Built-in translation system for all labels
- Type-safe: Full TypeScript support
- Mini-map & Controls: Navigation tools for complex trees
- Theme Support: Dark/light mode with customizable backgrounds
- Production Ready: Full-featured form generation and validation system
- 16 Input Types: text, number, select, checkbox, radio, date, daterange, time, timerange, file, address, http, textarea, password, switch, autocomplete, and hidden
- HTTP Integration: Built-in API integration with response mapping and search functionality
- Advanced Validation: Required fields, pattern matching, custom validation functions
- Conditional Logic: Dynamic field visibility based on user input and conditional edges
- Web & Native: Both web (React) and React Native renderer implementations
- Fully Customizable: Override any component (FormWrapper, Group, Inputs, SubmitButton, UI elements)
- Theme Support: Dark/light mode out of the box
- Google API Integration: Address autocomplete support
- Modular: Import only what you need (editor, renderer, or both)
- Modern Stack: React 18/19, TailwindCSS 4, TypeScript 5
- Well-typed: Comprehensive TypeScript definitions
- Production Ready: Battle-tested and actively maintained
# npm
npm install treege
# pnpm
pnpm add treege
# yarn
yarn add treege
# bun
bun add treegeCreate and edit decision trees visually:
import { TreegeEditor } from "treege/editor";
import type { Flow } from "treege";
function App() {
const [flow, setFlow] = useState<Flow | null>(null);
const handleSave = (updatedFlow: Flow) => {
setFlow(updatedFlow);
console.log("Decision tree saved:", updatedFlow);
};
return (
<TreegeEditor
flow={flow}
onSave={handleSave}
/>
);
}Render interactive forms from decision trees:
import { TreegeRenderer } from "treege/renderer";
import type { Flow, FormValues } from "treege";
function App() {
const flow: Flow = {
id: "flow-1",
nodes: [
{
id: "start",
type: "input",
data: {
name: "username",
label: "Enter your username",
required: true
}
}
],
edges: []
};
const handleSubmit = (values: FormValues) => {
console.log("Form submitted:", values);
};
return (
<TreegeRenderer
flows={flow}
onSubmit={handleSubmit}
/>
);
}import { TreegeEditor } from "treege/editor";
import { TreegeRenderer } from "treege/renderer";
import { useState } from "react";
function App() {
const [flow, setFlow] = useState(null);
const [mode, setMode] = useState<"edit" | "preview">("edit");
return (
<div>
<button onClick={() => setMode(mode === "edit" ? "preview" : "edit")}>
{mode === "edit" ? "Preview" : "Edit"}
</button>
{mode === "edit" ? (
<TreegeEditor flow={flow} onSave={setFlow} />
) : (
<TreegeRenderer flows={flow} onSubmit={console.log} />
)}
</div>
);
}Treege provides three import paths for optimal bundle size:
// Import everything (editor + renderer + types)
import { TreegeEditor, TreegeRenderer } from "treege";
// Import only the editor
import { TreegeEditor } from "treege/editor";
// Import only the renderer
import { TreegeRenderer } from "treege/renderer";Navigation node that controls the flow between different parts of the tree.
{
type: "flow",
data: {
targetId: "next-node-id",
label: "Continue"
}
}Form input with validation, patterns, and conditional logic.
{
type: "input",
data: {
type: "text",
name: "email",
label: "Email Address",
required: true,
pattern: "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$",
errorMessage: "Please enter a valid email"
}
}Supported input types: text, number, textarea, password, select, radio, checkbox, switch, autocomplete, date, daterange, time, timerange, file, address, http, hidden
Container for organizing multiple nodes together.
{
type: "group",
data: {
label: "Personal Information"
}
}Display-only elements for visual organization and content display.
{
type: "ui",
data: {
type: "title", // or "divider"
label: "Welcome to the form"
}
}Supported UI types:
title- Display headings and titlesdivider- Visual separator between sections
Create dynamic flows with conditional logic:
{
type: "conditional",
data: {
conditions: [
{
field: "age",
operator: ">=",
value: "18"
},
{
field: "country",
operator: "===",
value: "US"
}
],
logicalOperator: "AND"
}
}Supported operators: ===, !==, >, <, >=, <=
Treege supports multiple languages out of the box:
{
type: "input",
data: {
label: {
en: "First Name",
fr: "Prénom",
es: "Nombre"
}
}
}Override default input renderers with your own:
import { TreegeRenderer } from "treege/renderer";
const CustomTextInput = ({ node }) => {
return <input className="my-custom-input" />;
};
<TreegeRenderer
flows={flow}
components={{
inputs: {
text: CustomTextInput
}
}}
/>Add custom validation logic:
<TreegeRenderer
flows={flow}
validate={(values, visibleNodes) => {
const errors = {};
if (values.password !== values.confirmPassword) {
errors.confirmPassword = "Passwords must match";
}
return errors;
}}
/>Control when validation occurs:
// Validate only on submit (default)
<TreegeRenderer validationMode="onSubmit" />
// Validate on every change
<TreegeRenderer validationMode="onChange" />Use the HTTP input type to fetch and map data from APIs:
{
type: "input",
data: {
type: "http",
name: "country",
label: "Select your country",
httpConfig: {
method: "GET",
url: "https://api.example.com/countries",
responsePath: "$.data.countries", // JSONPath to extract data
mapping: {
label: "name",
value: "code"
},
searchParam: "query", // Enable search functionality
fetchOnMount: true
}
}
}Configure the renderer globally using the TreegeConfigProvider:
import { TreegeConfigProvider } from "treege/renderer";
function App() {
return (
<TreegeConfigProvider
config={{
language: "fr",
googleApiKey: "your-google-api-key",
components: {
// Your custom components
}
}}
>
<TreegeRenderer flows={flow} />
</TreegeConfigProvider>
);
}Use the useTreegeRenderer hook for programmatic control:
import { useTreegeRenderer } from "treege/renderer";
function CustomForm() {
const { values, setFieldValue, submit, reset } = useTreegeRenderer();
return (
<div>
<button onClick={() => setFieldValue("email", "[email protected]")}>
Prefill Email
</button>
<button onClick={submit}>Submit</button>
<button onClick={reset}>Reset</button>
</div>
);
}Check out the /example directory for complete examples:
# Run the example app
bun example| Prop | Type | Default | Description |
|---|---|---|---|
flow |
Flow | null |
null |
Initial decision tree |
onSave |
(flow: Flow) => void |
- | Callback when tree is saved |
language |
string |
"en" |
UI language |
theme |
"light" | "dark" |
"dark" |
Editor theme |
| Prop | Type | Default | Description |
|---|---|---|---|
flows |
Flow | null |
- | Decision tree to render |
onSubmit |
(values: FormValues) => void |
- | Form submission handler |
onChange |
(values: FormValues) => void |
- | Form change handler |
validate |
(values, nodes) => Record<string, string> |
- | Custom validation function |
initialValues |
FormValues |
{} |
Initial form values |
components |
RendererComponents |
- | Custom component overrides |
language |
string |
"en" |
UI language |
validationMode |
"onSubmit" | "onChange" |
"onSubmit" |
When to validate |
theme |
"light" | "dark" |
"dark" |
Renderer theme |
googleApiKey |
string |
- | API key for address input |
# Install dependencies
yarn install
# Start dev server
yarn dev
# Build library
yarn build
# Run linter and type check
yarn lint
# Preview build
yarn preview- React 18/19 - UI library
- TypeScript - Type safety
- TailwindCSS 4 - Styling
- ReactFlow - Node-based UI
- Radix UI - Accessible components
- Zustand - State management
- Vite - Build tool
Contributions are welcome! Please feel free to submit a Pull Request.
ISC
Created and maintained by Mickaël Austoni