Skip to content

ContainerRow

One container with its state, image, uptime, ports, usage and actions. Pick it for a list of containers or services; the demo changes state, shows a busy row and confirms with a polite message.

  • ContainerRow

PreviewLink to the section Preview

Live in all three themes. Everything here is interactive.

Light theme, ContainerRow

Runningwebshop-web-1Healthynode:26-alpineUp 3 hoursOpen in the browser :5173→51732.4% · 128 MiB (3.1%)
Unhealthydbshop-db-1Unhealthypostgres:18Up 12 minutesOpen in the browser :5432→5432
Crashedworkershop-worker-1Exit code 137registry.example.com/shop/worker-with-a-long-image-name:2026.11.08-build.4512Exited 2 minutes ago
Pausedcacheshop-cache-1valkey:9PausedOpen in the browser :6379→6379:5353→53/udp
Stoppedmailshop-mail-1axllent/mailpitStopped

Dark theme, ContainerRow

Runningwebshop-web-1Healthynode:26-alpineUp 3 hoursOpen in the browser :5173→51732.4% · 128 MiB (3.1%)
Unhealthydbshop-db-1Unhealthypostgres:18Up 12 minutesOpen in the browser :5432→5432
Crashedworkershop-worker-1Exit code 137registry.example.com/shop/worker-with-a-long-image-name:2026.11.08-build.4512Exited 2 minutes ago
Pausedcacheshop-cache-1valkey:9PausedOpen in the browser :6379→6379:5353→53/udp
Stoppedmailshop-mail-1axllent/mailpitStopped

High contrast theme, ContainerRow

Runningwebshop-web-1Healthynode:26-alpineUp 3 hoursOpen in the browser :5173→51732.4% · 128 MiB (3.1%)
Unhealthydbshop-db-1Unhealthypostgres:18Up 12 minutesOpen in the browser :5432→5432
Crashedworkershop-worker-1Exit code 137registry.example.com/shop/worker-with-a-long-image-name:2026.11.08-build.4512Exited 2 minutes ago
Pausedcacheshop-cache-1valkey:9PausedOpen in the browser :6379→6379:5353→53/udp
Stoppedmailshop-mail-1axllent/mailpitStopped

UsageLink to the section Usage

tsx
import { ContainerRow } from '@skribly/ui/ops'
tsx
<List aria-label={t('docker.containers')} items={containers} emptyState={t('docker.none')}>
  {(c) => (
    <ContainerRow id={c.id} name={c.service} secondaryName={c.name} state={runState(c)}
      stateLabel={t(`docker.state.${runState(c)}`)} image={c.image} status={c.status}
      ports={c.ports.map((p) => ({ host: p.hostPort, container: p.containerPort, href: url(p), label: t('docker.openPort') }))}
      isBusy={busy === c.id} busyLabel={t('docker.working', { name: c.service })}
      actions={<IconButton label={t('docker.restart', { name: c.service })} size="sm" onPress={() => restart(c)}><RotateCw aria-hidden /></IconButton>} />
  )}
</List>

Every label is a prop, so the app passes its own words in its own language. See no built-in text.

AccessibilityLink to the section Accessibility

  • The list is one tab stop; arrow keys move between containers and Right reaches the links and buttons in a row.
  • The state is a shaped glyph and a word, never colour alone.
  • Port links start their name with what is seen.
  • A busy row shows a named spinner and its buttons wait.
  • Actions wrap under the text on a narrow row, and every button clears 24px.

This demo runs through axe in all three themes on every test run. See what the tests check.

Search this site

Arrows move through the results, Enter opens one, Esc closes. Ctrl K /