Lists and content

Row

A mark, the title with a badge and the time on one line, one muted line under it. The whole row is the link.

openvibe-shared/kitJSON

Build it

kit.list([kit.row({ href: '/@goosely', mark: kit.mark({ name: 'goosely' }), title: 'goosely', badge: kit.badge('live', 'live'), meta: '2 h', sub: 'Seattle at night, chat picks the route' })])

Props

rel
string?
sub
string?
href
any?
mark
string?
meta
string?
attrs
any?
badge
string?
title
string?
trail
string?
unread
number?
metaIso
string?
subHtml
any?
titleHtml
any?

Anatomy

  • marka picture, or up to two letters on a colour from the name; size size.avatar
  • titlecolor color.text.primary; weight type.weight.bold
  • metathe time, on the title's line; color color.text.muted; size type.size.meta
  • subone line, cut with …; color color.text.muted; size type.size.meta
  • traila count, a switch or a button

Behaviour and access

Keyboard
Standard focus order
Outside tap
Leaves it open
Scroll
The page still scrolls
Reduced motion
Remove movement; keep the state change.
Name
its title and sub-line
Target
the row, at least 56 px tall
Focus
Enter opens it

States

  • default
  • hover
  • pressed
  • focused
  • disabled

Tokens

  • size.avatar
  • color.text.primary
  • type.weight.bold
  • color.text.muted
  • type.size.meta

Android · Jetpack Compose

Row

@Composable fun OvRow(title: String, onOpen: (() -> Unit)? = null, sub: String? = null, meta: String? = null, mark: (@Composable () -> Unit)? = null, trail: (@Composable () -> Unit)? = null) { ListItem( headlineContent = { Text(title, fontWeight = FontWeight.Bold, maxLines = 1, overflow = TextOverflow.Ellipsis) }, supportingContent = sub?.let { { Text(it, maxLines = 1, overflow = TextOverflow.Ellipsis, fontSize = OvScale.TypeSizeMeta) } }, leadingContent = mark, trailingContent = trail ?: meta?.let { { Text(it, fontSize = OvScale.TypeSizeMeta) } }, modifier = (if (onOpen != null) Modifier.clickable(onClick = onOpen) else Modifier).heightIn(min = 56.dp), ) }

iOS · SwiftUI

struct OvRow: View { let title: String var sub: String? = nil var meta: String? = nil var body: some View { HStack(alignment: .firstTextBaseline) { VStack(alignment: .leading, spacing: 2) { Text(title).fontWeight(.bold).lineLimit(1) if let sub { Text(sub).font(.system(size: OvScale.typeSizeMeta)).foregroundStyle(OvTokens.colorTextMuted).lineLimit(1) } } Spacer() if let meta { Text(meta).font(.system(size: OvScale.typeSizeMeta)).foregroundStyle(OvTokens.colorTextMuted) } } .frame(minHeight: 56) .accessibilityElement(children: .combine) } }

Markup

Default

<ul class="ovk-list"><li class="ovk-row"><a href="/@goosely"><span class="ovk-mark" style="--ovk-hue:350" aria-hidden="true">GO</span><span class="ovk-row-main"><span class="ovk-row-top"><strong>goosely</strong><span class="ovk-badge ovk-badge--live">live</span><span class="ovk-row-meta">2 h</span></span><span class="ovk-row-sub"><span>Seattle at night, chat picks the route</span></span></span></a></li></ul>