table · neumorphic · 灵感来源:GOV.UK table / USWDS usa-table
零分隔线:表头凹下去,悬停把整行按下去
| 组件 | 类型 | 材质数 | 浏览量 | 更新 |
|---|---|---|---|---|
| 玻璃按钮 | 按钮 | 3 | 1 284 | 2026-10-24 |
| 玻璃输入框 | 输入 | 3 | 963 | 2026-10-30 |
| 玻璃抽屉 | 抽屉 | 3 | 12 407 | 2026-10-31 |
| 极简通知 | 通知 | 3 | 77 | 2026-10-19 |
| 拟态骨架屏 | 骨架 | 3 | 5 | 2026-10-12 |
Data Table · 拟态数据表 · 表格 / Neumorphic
做一个 Data Table(拟态数据表):
- 同一份 props(caption / columns / rows / className)
- 零分隔线:表头做成凹下去的带,行悬停 = 整行按下去
- 用 border-separate 而非 collapse,塌陷模式会裁掉 tr 的阴影
- 没有线也没有斑马纹,行数一多难横向追踪——只给行数少的清单用
- 对齐、滚动与只读边界同玻璃数据表
用这些 CSS 变量:--color-text --color-text-muted --neuro-bg --neuro-dark --neuro-light
灵感参考:GOV.UK table / USWDS usa-table--color-text --color-text-muted --neuro-bg --neuro-dark --neuro-light
悬停 / 焦点
(尚未接进整页场景)
/r/table--neumorphic.json
免外壳的 markdown 版:/llms/components/table--neumorphic.mdborder-separate 而不是 border-collapse:塌陷模式下 tr 的阴影会被裁掉framed=false:只留滚动容器,材质底不重复画import { type ReactNode } from 'react';
export interface TableColumn {
key: string;
header: string;
/** end = 数字列:表头与数值一起右对齐(GOV / Polaris 同一条) */
align?: 'start' | 'end';
/** 列宽只写 Tailwind 宽度类,不写 px 字面量 */
width?: string;
}
export interface TableRow {
id: string;
cells: Record<string, ReactNode>;
}
interface Props {
caption: string;
columns: TableColumn[];
rows: TableRow[];
/** false = 只留滚动容器,材质底交给外层面板(嵌在卡片里时不再套一层卡) */
framed?: boolean;
className?: string;
}
/** 拟态数据表:材质签名 = 同色挤出、零边框——分层靠凹陷与浮起,不靠线;悬停把整行按下去 */
export function NeumorphicTable({ caption, columns, rows, framed = true, className = '' }: Props) {
const last = columns.length - 1;
return (
<div
role="region"
aria-label={caption}
tabIndex={0}
className={`
overflow-x-auto outline-offset-2 rounded-2xl
${framed
? 'p-2 bg-[var(--neuro-bg)] shadow-[6px_6px_14px_var(--neuro-dark),-6px_-6px_14px_var(--neuro-light)]'
: ''}
${className}
`}
>
<table className="w-full min-w-[34rem] border-separate border-spacing-0 text-sm">
<caption className="sr-only">{caption}</caption>
<thead>
<tr className="bg-[var(--neuro-bg)] shadow-[inset_2px_2px_5px_var(--neuro-dark),inset_-2px_-2px_5px_var(--neuro-light)]">
{columns.map((c, i) => (
<th
key={c.key}
scope="col"
className={`
px-4 py-2.5 text-xs font-medium text-[var(--color-text-muted)] whitespace-nowrap
${c.align === 'end' ? 'text-right' : 'text-left'}
${i === 0 ? 'rounded-l-xl' : i === last ? 'rounded-r-xl' : ''}
${c.width ?? ''}
`}
>
{c.header}
</th>
))}
</tr>
</thead>
<tbody>
{rows.map((row) => (
<tr
key={row.id}
className="transition-shadow hover:shadow-[inset_2px_2px_5px_var(--neuro-dark),inset_-2px_-2px_5px_var(--neuro-light)]"
>
{columns.map((c, i) =>
i === 0 ? (
<th
key={c.key}
scope="row"
className="px-4 py-3 text-left font-medium text-[var(--color-text)] break-words rounded-l-xl"
>
{row.cells[c.key]}
</th>
) : (
<td
key={c.key}
className={`
px-4 py-3 text-[var(--color-text-muted)] break-words
${i === last ? 'rounded-r-xl' : ''}
${c.align === 'end' ? 'text-right tabular-nums whitespace-nowrap' : ''}
`}
>
{row.cells[c.key]}
</td>
),
)}
</tr>
))}
</tbody>
</table>
</div>
);
}
src/components/table/neumorphic/