Skip to main content
cngx-src documentation

CngxCardGrid

ComponentPrimaryOnPushNo encapsulationv0.1.0WCAG AA

projects/common/card/card-grid.component.ts

Import#

import { CngxCardGrid } from '@cngx/common/card'

Description#

Responsive card grid layout with intrinsic sizing, keyboard navigation, and reason-based empty-state template selection.

Uses CSS Grid with auto-fill + minmax for intrinsic responsiveness - no breakpoint management required.

Keyboard navigation is provided by CngxRovingTabindex as a host directive. Arrow keys navigate between cards; Enter/Space activates.

Basic grid

<cngx-card-grid minWidth="280px">
  <cngx-card>...</cngx-card>
  <cngx-card>...</cngx-card>
</cngx-card-grid>

With empty state

<cngx-card-grid [items]="items()" [emptyReason]="emptyReason()">
  @for (item of items(); track item.id) {
    <cngx-card>...</cngx-card>
  }
  <ng-template cngxCardGridEmpty="no-results">
    <cngx-empty-state title="No results" />
  </ng-template>
  <ng-template cngxCardGridEmpty>
    <cngx-empty-state title="Nothing here yet" />
  </ng-template>
</cngx-card-grid>

https://cngxjs.github.io/cngx/examples/#/common/card/card-grid/basic-grid https://cngxjs.github.io/cngx/examples/#/common/card/card-grid/density-variants https://cngxjs.github.io/cngx/examples/#/common/card/card-grid/empty-state-with-reason

Metadata#

Host#

Relationships

Index#

Inputs#

density#"compact" | "default" | "comfortable"
input()

Grid density level - controls gap and card padding via CSS custom properties.

default 'default'
input()

Reason why items are empty - selects the matching cngxCardGridEmpty template.

input()

Gap between grid items.

default 'var(--cngx-gap-md, 16px)'
items#readonly unknown[] | undefined
input()

Optional data source. When provided and empty, the grid shows the matching empty-state template. When omitted, the grid is a pure layout tool.

minWidth#string
input()

Minimum card width for the CSS Grid minmax() function.

default '280px'
semanticList#boolean
input()

Whether the grid should have role="list". Requires role="listitem" on each card.

default false

Bind an async state - drives loading and empty from a single source. When set, isLoading derives from state.isFirstLoad() and empty derives from state.isEmpty() (overrides [items]).

HostBindings#

BindingExpression
[attr.role]semanticList() ? "list" : null
[attr.aria-busy]isLoading() || null
[style.--cngx-card-grid-min]minWidth()
[style.--cngx-card-grid-gap]density() === "default" ? gap() : null
[class.cngx-card-grid--compact]density() === "compact"
[class.cngx-card-grid--comfortable]density() === "comfortable"

Default visuals for CngxCardGrid. The host carries .cngx-card-grid and lays its <cngx-card> children out via auto-fill + minmax() so the column count reflows with the viewport without a media-query ladder.

Density modifiers

  • --compact - tighter gap, pins --cngx-card-padding to sm so nested cards stay in sync with the grid's rhythm
  • --comfortable - wider gap, pins --cngx-card-padding to lg

Reaching into --cngx-card-padding is an intentional cross- component coupling: the density modifier owns both the gap and the matching card-inner spacing.

Inheritance

  • --cngx-card-grid-gap -> --cngx-space-md
  • --cngx-card-grid-min - leaf token, no fallback chain

Index#

Layout

--cngx-card-grid-min#<length>
Default value 280px

Minimum inline size of a single grid cell - auto-fill packs as many cells as fit before reflowing.

--cngx-card-grid-gap#<length>
Default value 16px

Gap between grid cells. Density modifiers re-pin this and the nested --cngx-card-padding.