Skip to content

Property List

Show a record's properties as rows of icon, label and value, each one editable.

import { PropertyAge, PropertyDate, PropertyList, PropertyListItem, PropertyMoney, PropertyPerson, PropertyProgress, PropertyStatus, PropertyTag, PropertyText } from '@youj/react'

Installation & usage

npm i @youj/react

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

Use a property list for the fields of one record in a detail panel or a drawer: a deal's owner, stage and value, a ticket's assignee and priority, a file's size and dates. Each row is an icon, a label and a value, and the value is any node. Helpers lay out the common kinds and format them in the app's locale. For many records side by side, use a data table. For a form people fill in from scratch, use Field.

import { BanknoteIcon, CircleDashedIcon, CircleUserIcon } from '@youj/icons'
import { PropertyList, PropertyListItem, PropertyMoney, PropertyPerson, PropertyStatus } from '@youj/react'

export function DealProperties({ deal }: { deal: Deal }) {
  return (
    <PropertyList>
      <PropertyListItem icon={<CircleUserIcon />} label="Owner">
        <PropertyPerson name={deal.owner.name} src={deal.owner.avatar} />
      </PropertyListItem>
      <PropertyListItem icon={<CircleDashedIcon />} label="Stage">
        <PropertyStatus tone="warning">Proposal</PropertyStatus>
      </PropertyListItem>
      <PropertyListItem icon={<BanknoteIcon />} label="Value">
        <PropertyMoney value={deal.value} currency="USD" />
      </PropertyListItem>
    </PropertyList>
  )
}

The label column is 9rem wide and every value starts after it. Set --property-label-width on the list (className="[--property-label-width:--spacing(28)]") for shorter or longer labels. A long value truncates on one line; PropertyText shows the full text on hover. When the list is narrower than 20rem, each label sits above its value.

HelperShows
PropertyPersonan avatar (a photo, or the initials) and the name
PropertyTaga quiet Badge; any Badge variant passes through
PropertyStatusa colored dot and its label; tone is neutral, accent, success, warning, danger or a chart tone
PropertyProgressa bar and its percent, named by the row's label
PropertyDatea date in a <time>; format takes Intl.DateTimeFormat options
PropertyMoneyan amount in its currency, whole amounts without cents
PropertyAgehow long since since: "12 days", "3 months", "2 years"
PropertyTexttext that truncates

Reference

Propsstack, icon, label, onEdit (4)

Props

PropertyList

PropertyList props
PropType
stackboolean

Below 20rem of its own width, each row stacks its label above its value. false keeps them side by side at any width.

default true

true
Other props pass through: extends ComponentProps<'dl'>.

PropertyListItem

PropertyListItem props
PropType
iconReactNode

The label's icon, drawn muted at 16px.

–
labelRequiredstring

What the value is: "Owner", "Stage".

–
childrenReactNode

The value: text or one of the Property* helpers.

–
onEdit() => void

Shows an edit button on the row, named "Edit <label>".

–
Other props pass through: extends ComponentProps<'div'>.

PropertyList is a dl and takes its props. PropertyAge takes since and now; pass now from the server so the text is the same after hydration. PropertyDate, PropertyMoney and PropertyAge take locale, defaulting to the app's.

AccessibilityDescription list, edit buttons

Accessibility

  • It is a description list: each row is a dt and its dd, so a screen reader reads every label with its value.
  • Icons and the status dot are decorative (aria-hidden). The label and the status text carry the meaning.
  • PropertyProgress is a progressbar named by its row's label, with its value as text.
  • Edit buttons are named "Edit" and the row's label (editProperty in YoujProvider's labels), and stay in the tab order while hidden, showing as soon as they take focus.