Job Card

The canonical open-role block: a category badge, the role title, a one-line summary and a meta tier of location, employment type and salary band. Renders as a chrome-less row or a bordered card.

Marketing
Senior Graphic Designer

Lead creative projects to elevate brand identity and visual storytelling.

San Francisco, CAFull-time$80,000 – $120,000

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add job-card

Usage#

Compose the parts you need and omit the rest: there is no showX prop anywhere on this component. A role with no summary simply leaves out JobCardDescription; a board that links whole rows instead of showing a button leaves out JobCardAction. The eyebrow is an ordinary Badge dropped as the first child of JobCardContent, so it takes any tone in the Badge scale.

Variants#

plain (the default) is chrome-less: the row sits flush on whatever holds it, and the list that owns it paints the hairline between rows. card gives the role a box of its own: the boundary and nothing else, drawn straight on the page ground with no fill behind it, and with an inset ring rather than a border so the corner stays concentric with the radius inside it.

UX Researcher

Conduct user research to drive product design decisions.

Seattle, WAFull-time$70,000 – $100,000
Product Manager

Lead the development of cutting-edge product solutions.

Boston, MAFull-time$100,000 – $150,000

Layouts#

split (the default) rides the action against the right edge, vertically centred. stacked drops it below the content, which is what a card in a narrow column wants. inline is the table shape: title and meta share one line, and the meta becomes equal-width auto columns so the same template repeats on every row and the columns line up down the whole board. Both row layouts start as a stacked column and only become a row at their breakpoint (smfor split, md for inline), so an action never strands itself in the corner of a narrow frame.

Structural Engineer

Design and analyze structural components for residential projects.

San Francisco, CAFull-time$95,000 – $125,000
Corporate Lawyer
New York, NYFull-time$90,000 – $150,000

Divided rows#

divided turns a stack of plain rows into a board: a hairline under each one and the vertical band that gives the row its height. It is a rule of its own rather than a border-b, so it stays straight even under a rounded interactive row. Compose it as a real list, one <li> per role and no gap between them: the hairline is the separation, and the trailing rule is dropped from the last list item so the board does not close with a line under nothing.

  • Software Engineer
    Austin, TXFull-time$70,000 – $110,000
  • Content Designer
    Portland, ORFull-time$85,000 – $115,000
  • Clinical Research Coordinator
    Chicago, ILFull-time$60,000 – $95,000

Interactive rows#

Pass interactive (with asChild and an <a> child) when the whole row opens the role. A plain interactive row pulls its hover fill back into a detached rounded panel so the wash does not bleed to the container edge, while the text stays flush-aligned, and the hairline pulls in by the same amount so it never overhangs the text. There is no press scale: a row that shrinks pulls its fill off the edges it sits against and starts reading as a floating tile, so the press is a deepening fill instead.

Any action, not just a button#

JobCardAction is a plain slot, so a board that wants to show who is hiring drops an AvatarGroup into it instead of a button. Nothing about the recipe changes.

Senior Product Designer

Be part of creating innovative product experiences.

San Francisco, CAFull-time$90,000 – $120,000
MTN

API reference#

JobCard

The root <div>. Forwards all native <div> props.

  • variant: "plain" (default) | "card".
  • layout: "split" (default) | "stacked" | "inline".
  • divided: boolean; the hairline rule under the row, plus the vertical band that gives the row its height. A divided list has no gap between rows by definition, so the row supplies its own. Expects a list-item wrapper: the trailing rule is dropped from the last <li>, not from the card itself.
  • interactive: boolean; hover/press/focus affordance for a row that is itself a link.
  • asChild: boolean; render via Radix Slot, e.g. as an <li> or <a>.

JobCardMetaItem

One meta fact. Forwards native <span> props.

  • icon: ReactNode; the leading 20px glyph. A node rather than a component type so one item can pass a Phosphor icon and the next a JobCardFlag.

JobCardFlag

A country flag cropped into a ringed circle, sized to the meta glyph and marked decorative (the country is already spelled out beside it).

  • country: string; an ISO 3166-1 alpha-2 code, matching the iso2 field of the shared countries dataset.

JobCardContent, JobCardTitle, JobCardDescription, JobCardMeta, JobCardAction

The block parts: the text column, the role title (a <div> by default, with asChild for a real heading), the muted summary, the meta tier, and the trailing action slot. Each forwards its native element props, and each is optional.

FAQ#

Reach for JobCard when the row is an open role. List is the compact settings or member row: text-sm, a truncating title, and meta pinned right on the same line. JobCard is a marketing-scale block whose meta is a third tier under the summary and is allowed to wrap. Card is the generic surface with no opinion about its contents.