Rows

Compact key-value and surface rows. Expanded content renders as explicit Rows.Group or Rows.Panel siblings so regular and virtualized lists share the same model.

Pane

Network
Tempo
Fee
EmailValidator
Limited
DomainIntel
Unlimited

Surface

Tempo WalletSession restored
Now

Grouping

Use Rows.Group for nested rows and Rows.Panel for expanded content. The trigger row only owns the chevron state with action={{ type: "expand", expanded }}.

Usage

import { useEffect, useState } from 'react'
import { Rows } from 'regen-ui'

export function TransactionRows() {
  const [loadingOpen, setLoadingOpen] = useState(false)
  const [reviewOpen, setReviewOpen] = useState(false)

  return (
    <Rows>
      <Rows.Row label="Network">Tempo</Rows.Row>
      <Rows.Row action={{ type: 'navigation' }} label="Recipient" onClick={() => {}}>
        0xd8dA…6045
      </Rows.Row>
      <Rows.Row
        action={{
          expanded: reviewOpen,
          type: 'expand',
        }}
        label="Details"
        onClick={() => setReviewOpen((open) => !open)}
      >
        Sponsored
      </Rows.Row>
      {reviewOpen && (
        <Rows.Panel>
          <div className="grid gap-[8px] py-[10px] label-13">
            <div className="flex items-center justify-between gap-[12px]">
              <span className="text-foreground-secondary">Chain ID</span>
              <span className="tabular-nums">42431</span>
            </div>
            <div className="flex items-center justify-between gap-[12px]">
              <span className="text-foreground-secondary">Fees</span>
              <span>Sponsored</span>
            </div>
          </div>
        </Rows.Panel>
      )}
      <Rows.Row
        action={{
          expanded: loadingOpen,
          type: 'expand',
        }}
        label="Loading"
        onClick={() => setLoadingOpen((open) => !open)}
      >
        Pending
      </Rows.Row>
      {loadingOpen && (
        <Rows.Panel>
          <Rows.PanelLoader />
        </Rows.Panel>
      )}
    </Rows>
  )
}

export function SurfaceRows() {
  const [activityOpen, setActivityOpen] = useState(true)
  const [syncLoaded, setSyncLoaded] = useState(false)
  const [syncLoading, setSyncLoading] = useState(false)
  const [syncOpen, setSyncOpen] = useState(false)

  useEffect(() => {
    if (!syncLoading) return
    const timeout = setTimeout(() => {
      setSyncLoaded(true)
      setSyncLoading(false)
    }, 700)
    return () => clearTimeout(timeout)
  }, [syncLoading])

  const onSyncOpenChange = (open: boolean) => {
    setSyncOpen(open)
    if (open && !syncLoaded) setSyncLoading(true)
    if (!open) {
      setSyncLoaded(false)
      setSyncLoading(false)
    }
  }

  return (
    <Rows dividers="full" variant="surface">
      <Rows.Row
        action={{
          expanded: activityOpen,
          type: 'expand',
        }}
        onClick={() => setActivityOpen((open) => !open)}
      >
        <div className="flex flex-1 flex-col truncate">
          <span>Access key activity</span>
          <span className="text-foreground-secondary">2 transactions</span>
        </div>
      </Rows.Row>
      {activityOpen && (
        <Rows.Group>
          <Rows.Row
            render={<a href="https://example.org" rel="noopener noreferrer" target="_blank" />}
          >
            <div className="flex flex-1 flex-col truncate">
              <span>Access key spend</span>
              <span className="text-foreground-secondary">EmailValidator</span>
            </div>
            <span className="text-foreground-secondary">Now</span>
          </Rows.Row>
          <Rows.Row
            render={<a href="https://example.org" rel="noopener noreferrer" target="_blank" />}
          >
            <div className="flex flex-1 flex-col truncate">
              <span>Session closed</span>
              <span className="text-foreground-secondary">DomainIntel</span>
            </div>
            <span className="text-foreground-secondary">1m</span>
          </Rows.Row>
        </Rows.Group>
      )}
      <Rows.Row
        action={{
          expanded: syncOpen,
          type: 'expand',
        }}
        onClick={() => onSyncOpenChange(!syncOpen)}
      >
        <div className="flex flex-1 flex-col truncate">
          <span>Syncing activity</span>
          <span className="text-foreground-secondary">
            {syncLoading ? 'Loading rows' : syncLoaded ? '2 rows loaded' : 'Loads on open'}
          </span>
        </div>
      </Rows.Row>
      {syncOpen && (syncLoading || syncLoaded) && (
        <Rows.Group>
          {syncLoading ? (
            <Rows.RowGroupLoader />
          ) : (
            <>
              <Rows.Row
                render={
                  <a href="https://example.org" rel="noopener noreferrer" target="_blank" />
                }
              >
                <div className="flex flex-1 flex-col truncate">
                  <span>Recipient checked</span>
                  <span className="text-foreground-secondary">0xd8dA…6045</span>
                </div>
                <span className="text-foreground-secondary">Now</span>
              </Rows.Row>
              <Rows.Row
                render={
                  <a href="https://example.org" rel="noopener noreferrer" target="_blank" />
                }
              >
                <div className="flex flex-1 flex-col truncate">
                  <span>Policy refreshed</span>
                  <span className="text-foreground-secondary">DomainIntel</span>
                </div>
                <span className="text-foreground-secondary">Now</span>
              </Rows.Row>
            </>
          )}
        </Rows.Group>
      )}
    </Rows>
  )
}

API Reference

Rows.Props

childrenRequired
TypeReactNode
DefaultNone
Row items.
dividersOptional
Type'full' | 'inset'
DefaultRows.defaultDividers[variant]
Horizontal row divider length. Defaults to `'inset'` for pane rows and `'full'` for surface rows.
variantOptional
Type'pane' | 'surface'
Default'pane'
Visual row group surface.
Inherits HTMLAttributes<HTMLDivElement>.

Rows.Group.Props

Props for nested rows rendered with `Rows.Group`.

childrenRequired
TypeReactNode
DefaultNone
Nested row items.
Inherits HTMLAttributes<HTMLDivElement>.

Rows.Panel.Props

Props for expanded content rendered with `Rows.Panel`.

childrenRequired
TypeReactNode
DefaultNone
Panel content.
Inherits HTMLAttributes<HTMLDivElement>.

Rows.Row.Props

actionConditional
TypeActionExpand | ActionNavigation | ActionNone
Default'none'
Row action affordance.
onClickConditional
TypeOnClick
DefaultNone
Press handler. Update `action.expanded` and render adjacent content from here.Press handler.Press handler. When provided without `render` or a visual action, the row renders as a button.
childrenRequired
TypeReactNode
DefaultNone
Row content.
disabledOptional
Typeboolean
DefaultNone
Disable interaction when the row is interactive.
heightOptional
Typenumber
DefaultNone
Row height in px. Defaults to the variant height.
labelOptional
TypeReactNode
DefaultNone
Left-side label for key-value rows.
renderOptional
TypeReactElement
DefaultNone
Element to render as instead of a div or button.
spacingOptional
Type'both' | 'end' | 'none' | 'start'
Default'both'
Which sides keep the parent `<Rows>` padding. Only applies to pane rows.
Inherits HTMLAttributes<HTMLElement>, except action, onClick.

Rows.Row.ActionExpand

Expand row action. Shows a chevron for rows that open adjacent content such as `Rows.Group`.

expandedRequired
Typeboolean
DefaultNone
Whether the adjacent content is currently open.
typeRequired
Type'expand'
DefaultNone
Action type.

Rows.Row.ActionNavigation

Navigation row action.

typeRequired
Type'navigation'
DefaultNone
Action type.

Rows.Row.ActionNone

No visual row action.

typeRequired
Type'none'
DefaultNone
Action type.