容器
DescriptionList 描述列表
一条记录的各个字段,用真正的 <dl>,不是一堆 div 拼的网格。
用法
什么时候用它
import { DescriptionList } from '@misoto22/design'说明
一条记录的各个字段:标签、值、标签、值。
这是任何详情页里重复得最多的那个形状,也是最常被人用一堆 <div> 拼成网格手搓出来的那个——而那样一拼,标记原本携带的唯一一件事就没了。<dl> 告诉读屏软件“Owner”命名的是它旁边那个东西;一堆 div 拼的网格告诉它的是这里有两列互不相干的文字,配对关系只能靠阅读顺序去猜。
有好几条记录时请改用 Table。这个是正面看一条记录,表格是从上往下看很多条。
每一对都包在一个 <div> 里——HTML 规范允许 <dl> 里出现它,正是为了让一对可以作为一个整体来排版——所以那条细线能贯穿整行,而不是断在列间距里。
items 为空时渲染 null,而不是一个空的带边框的盒子。一条一个字段都没有的记录,是上面那个页面该用 EmptyState 去处理的状态;而一圈围着空气的细线,看起来就像一个没加载出来的组件。
结构
| 部件 | 说明 |
|---|---|
| List必填 | The <dl>. It is the element that carries the pairing: a grid of divs looks identical and tells a screen reader there are two columns of unrelated text. |
| Pair必填 | A <div> around each dt/dd, which the HTML specification allows inside a <dl> precisely so a pair can be laid out as a unit. It is what the hairline is drawn on, so the rule crosses the whole row rather than stopping in the column gap. |
| Term必填 | item.term, rendered as <dt> at --ink-3-aa. In the row layout it holds a 12rem column at sm and above and stacks below it, because a 12rem label column on a phone leaves the value about eight characters wide. |
| Description必填 | item.description, rendered as <dd> at --ink-2 with its browser margin reset. It takes a node, not a string, so a value can be a Badge, a link or a Timestamp. |
| Hairline | divided, on by default: a --rule under every pair but the last. Turn it off inside a Card, which already has an edge of its own. |
实践建议
推荐
- Let it render nothing when items is empty. It returns null rather than an empty bordered box, so the page above is free to show an EmptyState instead of a hairline around no content.
- Put an element in description when the value is a state or a link — it is a <dd>, so a Badge, an anchor or a Timestamp belongs there and a string of text does not have to be faked into one.
- Pass id on each item when rows are added, removed or reordered. The index is the key without one, which is right for the fixed field list a record page renders and wrong for a list that changes shape.
避免
- Do not reach for it to show several records. Every dt would repeat down the page and a reader comparing two records has to hold both in their head — that is what a Table’s column headings exist to avoid.
- Do not use layout="row" inside a narrow sidebar. It only collapses on the sm breakpoint, which is the viewport, not the container — a 12rem label column inside a 20rem panel leaves nothing for the value. Use layout="stacked" there.
示例
record fields
A record seen from the front. The markup is a real dl/dt/dd, which is what tells a screen reader that "Owner" names the value beside it — a grid of divs looks identical and says nothing. The value is a node, so a state is a Badge and a date is a Timestamp rather than two strings formatted by hand.
- Owner
- Henry Chen
- Region
- ap-southeast-2
- Status
- Deployed
- Last deploy
row and stacked
The same three fields under both layouts. row is the record-page shape — the labels line up down one edge and a reader scans them rather than reading them — and it collapses to one column under the sm breakpoint, because a 12rem label column on a phone leaves the value about eight characters wide. stacked keeps the value under its label at every width, which is the answer for a container that is narrow by design rather than by viewport: a card, a sidebar, a popover. Pick by the container, not by the number of fields.
- Runtime
- Node 24 on Cloudflare Workers
- Region
- ap-southeast-2
- Build
- pnpm --filter @misoto22/design build
- Runtime
- Node 24 on Cloudflare Workers
- Region
- ap-southeast-2
- Build
- pnpm --filter @misoto22/design build
a metadata rail
The shape it was built for: a detail page with the record on the left and its metadata in a rail beside it. The rail is stacked and undivided — it is already inside a bordered column, and a second set of hairlines inside one box is a grid pretending to be a table. Everything in the rail is a fact about the thing rather than part of it, which is the line to draw when deciding what belongs here: the title and the body are the record, the owner and the last deploy are what the page knows about it.
ui.misoto22.com
The documentation site for the design package. Statically exported, so every page is HTML on a CDN and the only JavaScript is the parts a reader touches.
类型
export type DescriptionListLayout = 'row' | 'stacked'无障碍
- 真正的 <dl>、<dt> 和 <dd>,读屏软件靠它才知道一个标签命名的是它旁边那个值。
- 每一对包在一个 <div> 里,规范允许 <dl> 里出现它,辅助技术也会直接读穿过去。
- 空列表渲染成 null,而不是一个空的 <dl>,所以不会有谁去播报一个一项都没有的列表。