Byline
An author · role · timestamp provenance line — for a record header, a comment, a
feed item, an audit note. The name is emphasis ink; the rest is secondary. One
class, plain markup, domain-neutral.
Not for packing actor, role and timestamp into a grid cell —
a stack of comments or feed entries each carrying their own byline is exactly
right, because each one is a separate thing the reader reads. A
table is not: packing actor and timestamp into one cell buries
the value that differs inside two that repeat, and neither can be
sorted or filtered on. Give them their own
data table columns — the
line is whether the reader scans DOWN a column, not how many items
there are. A cell carrying ONE value — a name, with
__avatar beside it — is not what that rules out: nothing
repeats, so nothing is buried, and it is the assignee column that
avatar documents.
Default
--compact — dense feeds & card sub-lines
__avatar — initials or a photo
Optional part, composed from the standalone
Avatar: the disc takes
BOTH classes — .bo-avatar paints it,
.bo-byline__avatar switches that one byline to a flex
row. The name already carries the identity as text, so the avatar
is aria-hidden — decoration, not a second copy of the
same information.
In context — heading an approval comment
Where bylines live: heading a comment or approval note on a record card, next to the audit trail that logs the same event in one line.
Markup
<span class="bo-byline"><strong>R. Vance</strong> · Requester · 10 Aug 2026</span> Quick reference generated
| Class | Role |
|---|---|
| .bo-byline | block (root) |
| .bo-byline--compact | variant: compact |
| .bo-byline__avatar | part: avatar |
API generated from CSS
| Blocks | bo-byline |
|---|---|
| Parts | bo-byline__avatar |
| Variants | bo-byline--compact |
| JS required | None — CSS-only. |
- Just markup + one class — wrap the name in
<strong>for emphasis ink. - Pairs with a record-type chip (
.bo-badge--type) in a widget header — see the record-detail pattern. - The
__avatarpart is decoration, not a caption —aria-hidden="true"always, since the name is already text in the byline itself.
Contrast — 11 AA pairs this component uses (generated, CI-gated)
| Text | on | Light | Dark |
|---|---|---|---|
| text-primary | bg-surface | 17.74 | 16.15 |
| text-primary | bg-canvas | 16.98 | 18.08 |
| text-secondary | bg-surface | 10.31 | 11.46 |
| text-secondary | bg-muted | 9.37 | 9.75 |
| bg-surface | text-primary | 17.74 | 16.15 |
| text-primary | bg-hover | 16.12 | 13.75 |
| text-primary | bg-selected | 17.01 | 11.86 |
| text-secondary | bg-selected | 9.88 | 8.41 |
| text-primary | bg-surface-raised | 17.74 | 14.51 |
| text-secondary | bg-canvas | 9.86 | 12.82 |
| text-primary | bg-muted | 16.12 | 13.75 |
Maturity generated
- Introduced
- v0.1.0
- CSS floor
- Chrome/Edge 105 · Firefox 121 · Safari 15.4
- Alignment scored
- 2026-08-23
- Assistive-tech evidence
- None recorded
Pin this component's first release with npm i @busy-office/ui@0.1.0.
The floor is derived from this component's stylesheet alone — set by
:has() — so it sits at or below the
whole framework's Chrome/Edge 119 · Firefox 129 · Safari 17.5.
No assistive-technology runtime result is recorded for any component: it needs a human listening to VoiceOver and NVDA on owner hardware; no gate in this repo can simulate announcement behaviour.
What automation covers instead is test:axe across every page at 1440 and 390, and check:forced-colors — see
accessibility.
Design-system alignment generated
100% (15/15) — how closely this component follows the design language. Each rule is scored 0-3 against a checkable citation; rules that don't apply leave the denominator. Scored 2026-08-23.
| Rule | Score | Evidence |
|---|---|---|
| Typography | 3 / 3 | sizes from --bo-font-size-sm/xs; no raw font-size |
| Colour | 3 / 3 | zero raw colour; name is emphasis ink, remainder secondary, both tokens |
| Spacing | 3 / 3 | zero raw dimension literals — the whole file is tokens |
| Interaction | n/a | plain markup, no behavior |
| Content | 3 / 3 | opener carries the wrong-choice clause: "Not for packing actor, role and timestamp into a grid cell" — a stack of comments each with a byline is right, but packing actor+timestamp into a table cell buries the differing value in two repeating ones and neither sorts; points at data-table columns, and names the one exception (a single-value name cell with __avatar). Blind re-scored 2026-08-23 (Polish round 2); the scorer caught the first draft drawing the line at "many rows", which contradicted the same opener's own recommendation for feed items — boundary redrawn at scanning DOWN a column. Headline re-cut 2026-09-05 (roadmap 273.3) from the POSITION to the PRACTICE: the framework's own two cell-borne bylines, on /components/avatar and /patterns/settings-admin, are name+avatar only, so the old headline forbade what its own reasoning did not. |
| Fit | 3 / 3 | record headers, comments, feed items, audit notes; composes .bo-avatar rather than owning a disc |