HapplyUI

Components

Info Card

Display labeled key-value detail items within a section card. Supports inline, grid, stacked, and wrapped layouts. Each item has a label and a custom-rendered value as children. The value container defaults to text-label-xs and text-sub-600 styling.


Installation

bunx @happlyui/cli@latest add info-card

Dependencies

npm packages

  • @remixicon/react

Registry dependencies

These are automatically installed when you add this component.

  • tv
  • happly-ui-utils
  • status-indicator

Usage

import * as InfoCard from "@/components/ui/info-card"

<InfoCard.Root layout="inline">
  <InfoCard.Item>
    <InfoCard.Label>Label</InfoCard.Label>
    <InfoCard.Value>Value content</InfoCard.Value>
  </InfoCard.Item>
</InfoCard.Root>

Examples

Inline

Items displayed side by side, each taking equal width. Uses Avatar for the user image.

Submitted date

Jan 3, 2025

Created by

Sean Muir
import { RiTimeLine } from '@remixicon/react'
import * as Avatar from '@/components/ui/avatar'
import * as InfoCard from '@/components/ui/info-card'

<InfoCard.Root layout="inline">
  <InfoCard.Item>
    <InfoCard.Label>Submitted date</InfoCard.Label>
    <InfoCard.Value>
      <RiTimeLine className="w-4 h-4" />
      <span>Jan 3, 2025</span>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Item>
    <InfoCard.Label>Created by</InfoCard.Label>
    <InfoCard.Value>
      <Avatar.Root size="20">
        <Avatar.Image src="avatar.jpg" />
      </Avatar.Root>
      <span>Sean Muir</span>
    </InfoCard.Value>
  </InfoCard.Item>
</InfoCard.Root>

Inline with Full Width Item

Mix inline and full-width items using the fullWidth prop. Uses StatusBadge for the status value and Avatar for the user image.

Submitted date

Jan 3, 2025

Created by

Sean Muir

Publication status

Require changes
import { RiAlertFill, RiTimeLine } from '@remixicon/react'
import * as Avatar from '@/components/ui/avatar'
import * as InfoCard from '@/components/ui/info-card'
import * as StatusBadge from '@/components/ui/status-badge'

<InfoCard.Root layout="inline">
  <InfoCard.Item>
    <InfoCard.Label>Submitted date</InfoCard.Label>
    <InfoCard.Value>
      <RiTimeLine className="w-4 h-4" />
      <span>Jan 3, 2025</span>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Item>
    <InfoCard.Label>Created by</InfoCard.Label>
    <InfoCard.Value>
      <Avatar.Root size="20">
        <Avatar.Image src="avatar.jpg" />
      </Avatar.Root>
      <span>Sean Muir</span>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Item fullWidth>
    <InfoCard.Label>Publication status</InfoCard.Label>
    <InfoCard.Value>
      <StatusBadge.Root status="pending">
        <StatusBadge.Icon as={RiAlertFill} />
        Require changes
      </StatusBadge.Root>
    </InfoCard.Value>
  </InfoCard.Item>
</InfoCard.Root>

Grid (2 Columns)

Items arranged in a fixed 2-column grid. Uses Badge for category and priority values.

Start date

Mar 1, 2025

End date

Jun 30, 2025

Category

Technology

Priority

High
import { RiCalendarLine } from '@remixicon/react'
import * as Badge from '@/components/ui/badge'
import * as InfoCard from '@/components/ui/info-card'

<InfoCard.Root layout="grid" columns={2}>
  <InfoCard.Item>
    <InfoCard.Label>Start date</InfoCard.Label>
    <InfoCard.Value>
      <RiCalendarLine className="w-4 h-4" />
      <span>Mar 1, 2025</span>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Item>
    <InfoCard.Label>End date</InfoCard.Label>
    <InfoCard.Value>
      <RiCalendarLine className="w-4 h-4" />
      <span>Jun 30, 2025</span>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Item>
    <InfoCard.Label>Category</InfoCard.Label>
    <InfoCard.Value>
      <Badge.Root variant="lighter" color="blue">
        Technology
      </Badge.Root>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Item>
    <InfoCard.Label>Priority</InfoCard.Label>
    <InfoCard.Value>
      <Badge.Root variant="lighter" color="red">
        High
      </Badge.Root>
    </InfoCard.Value>
  </InfoCard.Item>
</InfoCard.Root>

Stacked

Items stacked vertically, each taking full width. Uses Avatar and StatusBadge.

Application ID

#APP-2025-0142

Applicant

Jane Cooper

Status

Approved
import * as Avatar from '@/components/ui/avatar'
import * as InfoCard from '@/components/ui/info-card'
import * as StatusBadge from '@/components/ui/status-badge'

<InfoCard.Root layout="stack">
  <InfoCard.Item>
    <InfoCard.Label>Application ID</InfoCard.Label>
    <InfoCard.Value>
      <span>#APP-2025-0142</span>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Item>
    <InfoCard.Label>Applicant</InfoCard.Label>
    <InfoCard.Value>
      <Avatar.Root size="20">
        <Avatar.Image src="avatar.jpg" />
      </Avatar.Root>
      <span>Jane Cooper</span>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Item>
    <InfoCard.Label>Status</InfoCard.Label>
    <InfoCard.Value>
      <StatusBadge.Root status="completed" variant="light">
        <StatusBadge.Dot />
        Approved
      </StatusBadge.Root>
    </InfoCard.Value>
  </InfoCard.Item>
</InfoCard.Root>

With Action

Inline layout with a default action button. The action renders as a square button with an arrow icon.

Submitted date

Jan 3, 2025

Created by

Sean Muir
import { RiTimeLine } from '@remixicon/react'
import * as Avatar from '@/components/ui/avatar'
import * as InfoCard from '@/components/ui/info-card'

<InfoCard.Root layout="inline">
  <InfoCard.Item>
    <InfoCard.Label>Submitted date</InfoCard.Label>
    <InfoCard.Value>
      <RiTimeLine className="w-4 h-4" />
      <span>Jan 3, 2025</span>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Item>
    <InfoCard.Label>Created by</InfoCard.Label>
    <InfoCard.Value>
      <Avatar.Root size="20">
        <Avatar.Image src="avatar.jpg" />
      </Avatar.Root>
      <span>Sean Muir</span>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Action />
</InfoCard.Root>

Action with Notification

Action button with a notification dot in the top-right corner. Uses the StatusIndicator component internally.

Submitted date

Jan 3, 2025

Created by

Sean Muir

Created by

Sean Muir

Created by

Sean Muir

Created by

Sean Muir
import { RiTimeLine } from '@remixicon/react'
import * as Avatar from '@/components/ui/avatar'
import * as InfoCard from '@/components/ui/info-card'

<InfoCard.Root layout="inline">
  <InfoCard.Item>
    <InfoCard.Label>Submitted date</InfoCard.Label>
    <InfoCard.Value>
      <RiTimeLine className="w-4 h-4" />
      <span>Jan 3, 2025</span>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Item>
    <InfoCard.Label>Created by</InfoCard.Label>
    <InfoCard.Value>
      <Avatar.Root size="20">
        <Avatar.Image src="avatar.jpg" />
      </Avatar.Root>
      <span>Sean Muir</span>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Action notification />
</InfoCard.Root>

With Custom Action

Action button with a custom icon. Pass children to override the default arrow icon.

Application ID

#APP-2025-0142

Status

Approved
import { RiExternalLinkLine } from '@remixicon/react'
import * as InfoCard from '@/components/ui/info-card'
import * as StatusBadge from '@/components/ui/status-badge'

<InfoCard.Root layout="inline">
  <InfoCard.Item>
    <InfoCard.Label>Application ID</InfoCard.Label>
    <InfoCard.Value>
      <span>#APP-2025-0142</span>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Item>
    <InfoCard.Label>Status</InfoCard.Label>
    <InfoCard.Value>
      <StatusBadge.Root status="completed" variant="light">
        <StatusBadge.Dot />
        Approved
      </StatusBadge.Root>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Action>
    <RiExternalLinkLine className="size-5 text-icon-sub-600" />
  </InfoCard.Action>
</InfoCard.Root>

Grid (3 Columns)

Items arranged in a fixed 3-column grid. Uses Badge for the duration value.

Amount

$25,000

Duration

12 months

Deadline

Dec 31, 2025
import { RiCalendarLine } from '@remixicon/react'
import * as Badge from '@/components/ui/badge'
import * as InfoCard from '@/components/ui/info-card'

<InfoCard.Root layout="grid" columns={3}>
  <InfoCard.Item>
    <InfoCard.Label>Amount</InfoCard.Label>
    <InfoCard.Value>
      <span>$25,000</span>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Item>
    <InfoCard.Label>Duration</InfoCard.Label>
    <InfoCard.Value>
      <Badge.Root variant="stroke">
        12 months
      </Badge.Root>
    </InfoCard.Value>
  </InfoCard.Item>
  <InfoCard.Item>
    <InfoCard.Label>Deadline</InfoCard.Label>
    <InfoCard.Value>
      <RiCalendarLine className="w-4 h-4" />
      <span>Dec 31, 2025</span>
    </InfoCard.Value>
  </InfoCard.Item>
</InfoCard.Root>

API Reference

InfoCard.Root

The container for info card items. Controls layout and spacing.

PropTypeDefaultDescription
layout'inline' | 'grid' | 'stack' | 'wrap''inline'Controls how items are arranged.
columns1 | 2 | 3 | 4-Number of columns when layout is 'grid'.

InfoCard.Item

An individual card containing a label and value.

PropTypeDefaultDescription
fullWidthbooleanfalseWhen true, the item spans the full width of the container.

InfoCard.Label

The label text for an info card item.

PropTypeDefaultDescription

InfoCard.Value

The value container for custom-rendered content. Defaults to text-label-xs and text-text-sub-600 styling.

PropTypeDefaultDescription

InfoCard.Action

A square action button styled like an info card item. Renders a default RiArrowRightUpLine icon that can be overridden via children. Renders as an anchor tag when href is provided, otherwise a button.

PropTypeDefaultDescription
hrefstring-When provided, renders as an anchor tag instead of a button.
notificationbooleanfalseShow a notification dot in the top-right corner.

Previous
Theme Provider