react-nested-grid
v1.0.5
Published
A lightweight React component for rendering JSON-driven nested grid layouts.
Downloads
2,237
Maintainers
Readme
react-nested-grid
🃏 想要开箱即用的卡片 UI? 试试
@nested-grid/react-cards—— 本库的全新进化版,重构为 monorepo 架构:无头布局引擎(@nested-grid/core)、无头 React 绑定(@nested-grid/react),以及精装卡片预设 —— 直接提供带样式的<CardGroup>/<CardItem>、30 个 CSS 自定义属性的主题系统、hover 展开内容、按深度交替配色、itemOnlyGap叶子组紧凑间距,还有 15+ 真实场景布局示例(每个不到 100 行)。零 CSS 手写,完全可主题化,引入即用。npm install @nested-grid/react-cards
轻量级 React 组件,用于渲染 JSON 驱动的嵌套网格布局。

直接把 JSON 数据渲染成架构图、分组目录和其他层级布局。
适合:
- 嵌套仪表盘与分组面板
- 架构图或拓扑感界面
- 目录、画廊与层级展示界面
安装
npm install react-nested-grid快速开始
import { NestedGrid, type NestedGridNode } from 'react-nested-grid'
const nodes: NestedGridNode[] = [
{
id: 'inventory',
title: '库存管理',
columns: 2,
children: [
{
id: 'electronics',
title: '电子产品',
children: [
{ id: 'laptop', title: '笔记本电脑', content: '14" 和 16" 型号有货' },
{ id: 'monitor', title: '显示器', content: '4K USB-C 显示器' },
],
},
{
id: 'furniture',
title: '家具',
children: [
{ id: 'desk', title: '办公桌', content: '可调节升降桌' },
{ id: 'chair', title: '办公椅', content: '人体工学网布椅' },
],
},
],
},
]
export function App() {
return <NestedGrid nodes={nodes} />
}更多示例见 examples/。
节点结构
interface NestedGridNode<TData = unknown> {
// 身份 & 内容
id: React.Key
title?: React.ReactNode
content?: React.ReactNode
// 子节点 & 子网格
children?: NestedGridNode<TData>[]
columns?: number | string
gridStyle?: CSSProperties
virtual?: boolean
// 在父网格中的位置
span?: number
rowSpan?: number
cellStyle?: CSSProperties
// 自定义数据
data?: TData
}- 有
children的为分组(group),没有的为条目(item)。 title显示在 group 或 item 的头部。可选 — 没有标题的节点仍参与布局。content默认隐藏,hover 时展开(仅 item 有效)。使用showContent可始终显示。children为此 group 包含的子节点列表。columns设置子网格的grid-template-columns。number为repeat(n, minmax(0, 1fr))快捷方式。传string可使用任意 CSS 值(如"200px 1fr 1fr")。未设时回退到defaultColumns(默认1)。gridStyle向子网格容器透传额外 CSS 属性(如gridAutoRows、alignItems)。在columns和gap之后合并。virtual设为 true 时该节点仅用于布局,不渲染 group 包装,子节点直接放入网格单元。span让节点在父网格中跨多列。映射为gridColumn: span {n}。rowSpan让节点在父网格中跨多行。映射为gridRow: span {n}。cellStyle向单元容器透传额外 CSS 属性(如alignSelf、justifySelf、order)。在span/rowSpan之后合并。data为自定义数据,透传到渲染回调。
使用
NestedGrid
根组件。除 nodes 外所有属性均可选。
<NestedGrid
nodes={nodes}
defaultColumns={3}
groupGap={12}
itemGap={8}
showContent
onNodeClick={(node) => console.log(node.id)}
theme={{ itemHoverBg: '#2563eb', itemHoverColor: '#fff' }}
/>groupGap / itemGap 接受单值或 [行间距, 列间距] 元组。每层网格自动检测是否包含 group,自动选用对应间距。
NestedGridGroup & NestedGridItem
默认的分组和条目组件。均支持 theme、styles 和标准 HTML 属性。
import { NestedGrid, NestedGridGroup, NestedGridItem } from 'react-nested-grid'
<NestedGrid
nodes={nodes}
renderGroup={({ node, children, depth }) => (
<NestedGridGroup node={node} styles={{ header: { borderBottom: '1px solid #ddd' } }}>
{children}
</NestedGridGroup>
)}
renderItem={({ node }) => (
<NestedGridItem
node={node}
showContent
titleExtra={({ expanded }) => (expanded ? '▼' : '▶')}
styles={{ header: { writingMode: 'vertical-rl' } }}
/>
)}
/>| NestedGridItem 属性 | 类型 | 说明 |
|---|---|---|
| node | NestedGridNode | 要渲染的节点 |
| titleExtra | ReactNode \| ({ expanded }) => ReactNode | 标题旁的额外内容 |
| showContent | boolean(默认 false) | 始终展示内容 |
| styles | { header?, body? } | 子元素内联样式 |
| theme | NestedGridTheme | 单组件主题覆盖 |
| NestedGridGroup 属性 | 类型 | 说明 |
|---|---|---|
| node | NestedGridNode | 要渲染的分组节点 |
| children | ReactNode | 已渲染的子网格 |
| styles | { header?, body? } | 子元素内联样式 |
| theme | NestedGridTheme | 单组件主题覆盖 |
两者均继承 HTMLAttributes<HTMLDivElement>,className、style、onClick 等也可使用。
自定义渲染
renderGroup 和 renderItem 替换默认渲染。回调参数:
{ node, depth, index, parent, oriNode }renderGroup 额外接收 children(已渲染的子网格)。oriNode 为默认组件,只加包装时直接用。
<NestedGrid
nodes={nodes}
renderItem={({ node, oriNode }) => (
<a href={`/items/${node.id}`}>{oriNode}</a>
)}
/>Context & 工具函数
useNestedGridContext() 返回 { defaultColumns, groupGap, itemGap, theme, showContent, onNodeClick },用于构建自定义组件。
themeToVars(theme) 将 NestedGridTheme 转为 CSS 变量 style 对象。
样式
Theme
theme 属性设置 CSS 自定义属性,所有子组件继承。可传给 NestedGrid、NestedGridGroup 或 NestedGridItem,最近祖先优先。
import { type NestedGridTheme } from 'react-nested-grid'
const theme: NestedGridTheme = {
groupBorder: 'none',
groupBgEven: '#eef2ff',
groupBgOdd: '#e0e7ff',
groupTitleColor: '#4338ca',
itemBorder: 'none',
itemShadow: '0 1px 3px rgb(0 0 0 / 8%)',
itemHoverBg: '#4338ca',
itemHoverColor: '#fff',
contentFontSize: '13px',
contentColor: '#64748b',
contentAnimDuration: '150ms',
}所有 key 前缀为 --rng-(如 groupBgEven → --rng-group-bg-even)。
| Group | CSS 属性 | 默认值 |
|---|---|---|
| groupBorder | border | 1px solid #e5e7eb |
| groupBorderRadius | border-radius | 8px |
| groupBg | background | — |
| groupBgEven | background | — |
| groupBgOdd | background | — |
| groupTitleColor | color | — |
| groupTitleFontSize | font-size | — |
| groupTitleFontWeight | font-weight | 600 |
| groupPadding | padding | 8px 16px |
| groupHeaderPadding | padding | 0 |
| groupBodyPadding | padding | 8px 0 0 |
| Item | CSS 属性 | 默认值 |
|---|---|---|
| itemBorder | border | 1px solid #e5e7eb |
| itemBorderRadius | border-radius | 4px |
| itemBg | background | #ffffff |
| itemShadow | box-shadow | — |
| itemPadding | padding | 10px 12px |
| itemHoverBg | background(hover) | #f3f4f6 |
| itemHoverColor | color(hover) | — |
| itemTitleFontSize | font-size | — |
| itemTitleFontWeight | font-weight | 600 |
| Content | CSS 属性 | 默认值 |
|---|---|---|
| contentColor | color | — |
| contentFontSize | font-size | 13px |
| contentLineHeight | line-height | 20px |
| contentPaddingTop | padding-top(展开时) | 8px |
| contentAnimDuration | 过渡动画时长 | 200ms |
深度类名
每个 cell 自动添加 rng-depth-{n}、rng-depth-even / rng-depth-odd。
.rng-depth-0 > .rng-group { border-width: 2px; }
.rng-depth-even > .rng-group { background: #f1f5f9; }CSS 类名覆盖
theme 无法覆盖的细节,可直接覆盖 rng-* 类名:
.rng-item-title { text-transform: uppercase; }
.rng-node { min-width: 200px; }