Skip to content

Commit 1028224

Browse files
authored
Merge pull request #23253 from opf/implementation/75029-border-box-list-lookbook
[#75029] Document Border Box List in Lookbook
2 parents c6b88a2 + 1c386ff commit 1028224

7 files changed

Lines changed: 199 additions & 174 deletions

File tree

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
The `BorderBoxListComponent` displays compact, structured list items with
2+
optional section headers, item actions, empty states, and a footer.
3+
4+
## Overview
5+
6+
<%= embed OpenProject::Common::BorderBoxListComponentPreview, :default %>
7+
8+
## Anatomy
9+
10+
The list is structured in up to four parts:
11+
12+
**Header** *(optional)*
13+
Names the list section. It can show a count, description, action buttons, an
14+
action menu, and an optional collapse toggle. In static headers, the description
15+
renders below the heading line. In collapsible headers, the description is part
16+
of the collapsible header and is hidden when the list is collapsed.
17+
18+
**Items**
19+
The list rows. Items can render generic row content or a work package card.
20+
21+
**Empty state** *(optional)*
22+
Shown when the list has no items.
23+
24+
**Footer** *(optional)*
25+
Shown below the items. Use it for summary or follow-up content.
26+
27+
If a page shows multiple Border Box Lists and one list has a header, all
28+
comparable lists should use headers.
29+
30+
## Parameters
31+
32+
| Parameter | Type | Default | Description |
33+
|---|---|---|---|
34+
| `container` | `String`, `Symbol`, `Class`, `Object` | required | Seed used to derive stable DOM ids for the list, header, and footer |
35+
| `scheme` | `Symbol` | `:default` | Visual scheme. Use `:transparent` for list containers that should blend into their surrounding surface |
36+
| `padding` | `Symbol` | `:default` | Row padding forwarded to the underlying `Primer::Beta::BorderBox`. Supports Primer BorderBox padding values such as `:condensed`, `:default`, and `:spacious` |
37+
| `header_padding` | `Symbol` | `:inherit` | Header-only vertical padding override. Supports `:inherit`, `:condensed`, `:default`, and `:spacious` |
38+
| `interactive` | `Boolean` | `false` | Enables polite ARIA live-region announcements for counter and configured empty-state updates |
39+
| `collapsible` | `Boolean` | `false` | Renders the header as a collapsible toggle when a header is present |
40+
| `current_user` | `User` | `User.current` | User context forwarded to work package item rows |
41+
| `system_arguments` | `Hash` | `{}` | Forwarded to the underlying `Primer::Beta::BorderBox` |
42+
43+
## Slots
44+
45+
| Slot | Description |
46+
|---|---|
47+
| `with_header` | Optional section header. See [Header parameters](#header-parameters) and [Header slots](#header-slots) below |
48+
| `with_item` | Generic list row that renders the provided block content |
49+
| `with_work_package_item` | Work package row that renders a work package card |
50+
| `with_empty_state` | Empty-state content rendered when no items are present |
51+
| `with_footer` | Optional footer row below the list items |
52+
53+
## Header
54+
55+
### Header parameters
56+
57+
| Parameter | Type | Default | Description |
58+
|---|---|---|---|
59+
| `title` | `String` | required | Header title |
60+
| `title_tag` | `Symbol` | `:h4` | HTML tag for the title heading |
61+
| `title_arguments` | `Hash` | `{}` | Forwarded to the title heading element |
62+
| `count` | `Integer`, `Boolean`, `nil` | `nil` | Pass `true` to infer the rendered item count, an integer for an explicit value, or `nil`/`false` to hide it |
63+
| `count_arguments` | `Hash` | `{}` | Forwarded to `Primer::Beta::Counter`. Merged over defaults (`scheme: :primary`, `hide_if_zero: true`) |
64+
| `collapsed` | `Boolean` | `false` | Whether a collapsible header starts closed |
65+
66+
### Header slots
67+
68+
| Slot | Description |
69+
|---|---|
70+
| `with_description` | Secondary content below the title, wrapped in `Primer::Beta::Text` with muted color by default. Accepts Primer system arguments |
71+
| `with_action_button` | Button rendered in the header actions area |
72+
| `with_menu` | Action menu rendered in the header actions area. Pass `button_aria_label:` for the trigger button |
73+
74+
### Collapsible headers
75+
76+
Collapsible headers add:
77+
78+
- an **arrow indicator** next to the title to show whether the section is
79+
collapsed or expanded.
80+
- an optional **header description** that gives more context to the section and
81+
is hidden when the list is collapsed.
82+
- an optional **counter** that displays the number of items in the section.
83+
84+
When collapsed, the bottom border is slightly thicker to indicate that content
85+
is hidden.
86+
87+
Both static and collapsible headers can include additional actions. For example,
88+
a menu button can offer contextual actions such as edit, delete, move up, or
89+
move down.
90+
91+
<%= embed OpenProject::Common::BorderBoxListComponentPreview, :default, params: { collapsible: true } %>
92+
93+
## Variants
94+
95+
<%= embed OpenProject::Common::BorderBoxListComponentPreview, :playground, panels: %i[params source] %>
96+
97+
### Transparent scheme
98+
99+
Use the transparent scheme for list containers that should not render a visible
100+
header background or separator, such as Backlogs sprint and inbox containers.
101+
102+
<%= embed OpenProject::Common::BorderBoxListComponentPreview, :transparent, panels: %i[params source] %>
103+
104+
### Work package items
105+
106+
Use `with_work_package_item` for rows that should render a work package card.
107+
It renders `OpenProject::Common::WorkPackageCardComponent` by default. See the
108+
[Work Package Card documentation](/lookbook/pages/components/work_packages/card)
109+
for card-specific layout, parameters, and slots.
110+
111+
<%= embed OpenProject::Common::BorderBoxListComponentPreview, :with_work_package_items, panels: %i[source] %>
112+
113+
### Empty state
114+
115+
Use `with_empty_state` when the list can be rendered without items. It renders a
116+
`Primer::Beta::Blankslate` under the hood, accepting `title:`, `description:`,
117+
and `icon:` keywords.
118+
119+
<%= embed OpenProject::Common::BorderBoxListComponentPreview, :empty_state, panels: %i[source] %>
120+
121+
## Usage guidelines
122+
123+
Use the Border Box List for compact item collections such as:
124+
125+
- meeting agenda items.
126+
- project attributes in project settings.
127+
- configured OAuth applications.
128+
- work package lists with card-style rows.
129+
130+
If the content needs table structure with columns and column headers, use the
131+
[Border Box Table](./tables/border_box_table) component instead.
132+
133+
### Best practices
134+
135+
**Do**
136+
137+
- Use section headers when the items have logical categories, such as open and
138+
planned meetings.
139+
- Use the built-in header actions and item menus instead of composing raw
140+
BorderBox rows by hand.
141+
- Make headers and items draggable when users need to reorder sections or move
142+
items between sections.
143+
144+
**Don't**
145+
146+
- Don't mix sections with and without headers. If one section has a header, they must all have headers.
147+
- Don't make sections collapsible when users benefit from seeing all content at
148+
once.
149+
- Don't use the Border Box List for data that needs column alignment, sorting,
150+
or column headers.
151+
152+
## Technical notes
153+
154+
Use `OpenProject::Common::BorderBoxListComponent` instead of composing
155+
`Primer::Beta::BorderBox` directly when rendering OpenProject lists.
156+
Header descriptions are wrapped in `Primer::Beta::Text` with muted text color by
157+
default, and can receive Primer system arguments through `with_description`.
158+
159+
## Code structure
160+
161+
```ruby
162+
render OpenProject::Common::BorderBoxListComponent.new(
163+
container: "project-attributes",
164+
scheme: :transparent,
165+
header_padding: :default,
166+
padding: :condensed,
167+
collapsible: true
168+
) do |list|
169+
list.with_header(title: "Project attributes", count: true) do |header|
170+
header.with_description(id: "project-attributes-description", font_size: :small) do
171+
"Visible in the project overview"
172+
end
173+
header.with_menu(button_aria_label: "Project attribute actions") do |menu|
174+
menu.with_item(label: "Edit", href: edit_project_path(@project))
175+
end
176+
end
177+
178+
@project_attributes.each do |attribute|
179+
list.with_item { attribute.name }
180+
end
181+
182+
list.with_empty_state(
183+
title: "No attributes yet",
184+
description: "Add attributes to describe this project."
185+
)
186+
187+
list.with_footer { "Last updated: #{format_date(@project.updated_at)}" }
188+
end
189+
```
190+
191+
For lower-level details, see the [Primer BorderBox preview examples](/lookbook/inspect/primer/beta/border_box/playground).

lookbook/docs/components/border-box.md.erb

Lines changed: 0 additions & 56 deletions
This file was deleted.

lookbook/docs/components/inset-box.md.erb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ Some places where we already use the Inset Box:
3838

3939
It is useful whenever content should stand out from the page background while staying lightweight.
4040

41-
If content needs more structure (e.g., with headers, actions, or multiple items), consider using the Border Box component instead.
41+
If content needs more structure, such as headers, actions, or multiple items,
42+
consider using the Border Box List component instead.
4243

4344
## Best practices
4445

@@ -51,7 +52,8 @@ If content needs more structure (e.g., with headers, actions, or multiple items)
5152

5253
- Don’t apply arbitrary custom background colors in CSS — use the component’s options.
5354
- Don’t duplicate "grey box" styles manually; always use the Inset Box.
54-
- Don’t use Inset Box if a more structured component (like Border Box) is better suited.
55+
- Don’t use Inset Box if a more structured component, such as Border Box List,
56+
is better suited.
5557

5658
## Technical notes
5759

lookbook/docs/components/tables/border-box-table.md.erb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ Some examples of where we already use the Border Box table:
3131
- to display a list of configured OpenID providers
3232
- to display a list of configured SCIM clients
3333

34-
If the content does not need a table structure with column headers and grids, please use the simpler [Border Box](../border_box) component instead.
34+
If the content does not need a table structure with column headers and grids,
35+
please use the simpler [Border Box List](../border_box_list) component instead.
3536

3637
## Technical notes
3738

lookbook/previews/op_primer/border_box_component_preview.rb

Lines changed: 0 additions & 50 deletions
This file was deleted.

lookbook/previews/op_primer/border_box_component_preview/collapsible.html.erb

Lines changed: 0 additions & 64 deletions
This file was deleted.

0 commit comments

Comments
 (0)