Package Exports
- @domeadev/react-elements-renderer
Readme
React Elements Renderer
A flexible React component for rendering hierarchical/nested data structures with customizable rendering logic and automatic recursion handling.
Features
- 🔄 Recursive Rendering: Automatically handles nested/hierarchical data structures
- 🎯 Type Safe: Full TypeScript support with generic types
- 🎨 Flexible: Completely customizable element rendering
- 🔑 Key Management: Built-in key generation for React reconciliation
- 🌳 Tree Structures: Perfect for trees, menus, file systems, organizational charts, etc.
- ⚡ Lightweight: Zero dependencies (except React)
Installation
npm
npm install @domeadev/react-elements-rendereryarn
yarn add @domeadev/react-elements-rendererpnpm
pnpm add @domeadev/react-elements-rendererBasic Usage
import { ElementsRenderer } from "@domeadev/react-elements-renderer";
interface MenuItem {
id: number;
label: string;
children?: MenuItem[];
}
const menuItems: MenuItem[] = [
{
id: 1,
label: "Home",
},
{
id: 2,
label: "Products",
children: [
{ id: 21, label: "Laptops" },
{ id: 22, label: "Phones" },
],
},
];
function MenuComponent() {
return (
<ElementsRenderer
elements={menuItems}
getElementKey={(item) => item.id}
getChildElements={(item) => item.children}
renderElement={({ element, children }) => (
<div>
<span>{element.label}</span>
{children && <div style={{ marginLeft: 20 }}>{children}</div>}
</div>
)}
/>
);
}Advanced Usage
Parent-Child Relationships
When your data has parent-child relationships (like a flat array with parentId fields):
interface TreeNode {
id: number;
name: string;
parentId?: number;
}
const flatData: TreeNode[] = [
{ id: 1, name: "Root" },
{ id: 2, name: "Child 1", parentId: 1 },
{ id: 3, name: "Child 2", parentId: 1 },
{ id: 4, name: "Grandchild", parentId: 2 },
];
function TreeComponent() {
const rootNodes = flatData.filter((node) => !node.parentId);
return (
<ElementsRenderer
elements={rootNodes}
getElementKey={(node) => node.id}
getChildElements={(node) =>
flatData.filter((child) => child.parentId === node.id)
}
renderElement={({ element, children, index }) => (
<div style={{ paddingLeft: index * 20 }}>
<div>{element.name}</div>
{children}
</div>
)}
/>
);
}File System Tree
interface FileNode {
name: string;
type: "file" | "folder";
children?: FileNode[];
}
const fileSystem: FileNode[] = [
{
name: "src",
type: "folder",
children: [
{
name: "components",
type: "folder",
children: [
{ name: "Button.tsx", type: "file" },
{ name: "Input.tsx", type: "file" },
],
},
{
name: "utils",
type: "folder",
children: [{ name: "helpers.ts", type: "file" }],
},
{ name: "App.tsx", type: "file" },
],
},
];
function FileExplorer() {
return (
<ElementsRenderer
elements={fileSystem}
getElementKey={(node, index) => `${node.name}-${index}`}
getChildElements={(node) => node.children}
renderElement={({ element, children }) => (
<div>
<div
style={{
fontWeight: element.type === "folder" ? "bold" : "normal",
color: element.type === "folder" ? "#0066cc" : "#333",
}}
>
{element.type === "folder" ? "📁" : "📄"} {element.name}
</div>
{children && (
<div
style={{
marginLeft: 20,
borderLeft: "1px solid #ccc",
paddingLeft: 10,
}}
>
{children}
</div>
)}
</div>
)}
/>
);
}API Reference
ElementsRenderer Props
| Prop | Type | Required | Description |
|---|---|---|---|
elements |
T[] |
✅ | Array of elements to render |
getElementKey |
(element: T, index: number) => string | number |
✅ | Function to generate unique keys for React reconciliation |
renderElement |
(props: RenderElementProps<T>) => ReactNode |
✅ | Function to render each element |
getChildElements |
(element: T) => T[] | undefined |
❌ | Function to get child elements for recursion |
RenderElementProps<T>
The renderElement function receives an object with these properties:
| Property | Type | Description |
|---|---|---|
element |
T |
The current element being rendered |
childElements |
T[] | undefined |
Array of child elements (if any) |
children |
ReactNode |
Pre-rendered children components |
index |
number |
Index of the current element in its parent's children array |
Use Cases
This component is perfect for:
- 🌳 Navigation Menus: Multi-level dropdown menus
- 📁 File Explorers: Folder/file tree structures
- 🏢 Organizational Charts: Company hierarchy visualization
- 📋 Category Lists: Nested product categories
- 🗂️ Taxonomy Trees: Tag/category hierarchies
- 📊 Decision Trees: Flowchart-like structures
- 🎯 Sitemap Visualization: Website structure display
TypeScript Support
This package is built with TypeScript and provides full type safety:
interface MyElement {
id: string;
name: string;
children?: MyElement[];
}
// TypeScript will infer the correct types
<ElementsRenderer<MyElement>
elements={myElements}
getElementKey={(element) => element.id} // element is typed as MyElement
renderElement={(
{ element, children } // element is typed as MyElement
) => (
<div>
{element.name}
{children}
</div>
)}
getChildElements={(element) => element.children} // element is typed as MyElement
/>;Performance Considerations
- The component uses React keys for efficient reconciliation
- Child elements are only rendered when they exist
- Recursive rendering is optimized with React.Fragment
- No unnecessary re-renders thanks to proper key management
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
If you find this package useful, please consider:
- ⭐ Starring the repository
- 🐛 Reporting bugs
- 💡 Suggesting new features
- 📖 Improving documentation