Card

A container with header, content and footer parts.

import { … } from '@inlaylab/ivorie/card'
ProfileUpdate your name and email address.
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IV_FIELD_IMPORTS } from '@inlaylab/ivorie/field';
import { IV_INPUT_IMPORTS } from '@inlaylab/ivorie/input';
import { IvButton } from '@inlaylab/ivorie/button';

@Component({
  selector: 'demo-card',
  imports: [IV_CARD_IMPORTS, IV_FIELD_IMPORTS, IV_INPUT_IMPORTS, IvButton],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-sm">
      <iv-card-header>
        <iv-card-title>Profile</iv-card-title>
        <iv-card-description>Update your name and email address.</iv-card-description>
      </iv-card-header>
      <iv-card-content class="flex flex-col gap-4">
        <iv-field>
          <label ivLabel for="card-name">Name</label>
          <input ivInput id="card-name" value="Maya Ross" />
        </iv-field>
        <iv-field>
          <label ivLabel for="card-email">Email</label>
          <input ivInput id="card-email" type="email" value="maya@acme.dev" />
        </iv-field>
      </iv-card-content>
      <iv-card-footer class="gap-2">
        <button ivButton variant="outline">Cancel</button>
        <button ivButton class="ml-auto">Save changes</button>
      </iv-card-footer>
    </iv-card>
  `,
})
export default class CardDemo {}

Installation

CLInpm
npx ivorie add card

Usage

import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
<iv-card>
  <iv-card-header>
    <iv-card-title>Account</iv-card-title>
    <iv-card-description>Manage your preferences.</iv-card-description>
  </iv-card-header>
  <iv-card-content>Body</iv-card-content>
</iv-card>

Examples

Action

API keysKeys used to authenticate requests.
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IvButton } from '@inlaylab/ivorie/button';

@Component({
  selector: 'demo-card-action',
  imports: [IV_CARD_IMPORTS, IvButton],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-sm">
      <iv-card-header>
        <iv-card-title>API keys</iv-card-title>
        <iv-card-description>Keys used to authenticate requests.</iv-card-description>
        <iv-card-action>
          <button ivButton size="sm" variant="outline">Add key</button>
        </iv-card-action>
      </iv-card-header>
    </iv-card>
  `,
})
export default class CardActionDemo {}
Delete accountThis action cannot be undone.
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IvButton } from '@inlaylab/ivorie/button';

@Component({
  selector: 'demo-card-footer',
  imports: [IV_CARD_IMPORTS, IvButton],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-sm">
      <iv-card-header>
        <iv-card-title>Delete account</iv-card-title>
        <iv-card-description>This action cannot be undone.</iv-card-description>
      </iv-card-header>
      <iv-card-footer class="gap-2">
        <button ivButton variant="outline">Cancel</button>
        <button ivButton variant="destructive" class="ml-auto">Delete</button>
      </iv-card-footer>
    </iv-card>
  `,
})
export default class CardFooterDemo {}

Small

Quick statsLast 7 days.

1,284 visits

import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';

@Component({
  selector: 'demo-card-small',
  imports: [IV_CARD_IMPORTS],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card size="sm" class="w-full max-w-sm">
      <iv-card-header>
        <iv-card-title>Quick stats</iv-card-title>
        <iv-card-description>Last 7 days.</iv-card-description>
      </iv-card-header>
      <iv-card-content>
        <p class="text-sm">1,284 visits</p>
      </iv-card-content>
    </iv-card>
  `,
})
export default class CardSmallDemo {}

Image

IvorieIvorie Pro

Unlimited projects, custom themes and priority support.

import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';

@Component({
  selector: 'demo-card-image',
  imports: [IV_CARD_IMPORTS],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-sm">
      <img src="app.svg" alt="Ivorie" class="h-32 w-full object-contain p-4" />
      <iv-card-header>
        <iv-card-title>Ivorie Pro</iv-card-title>
      </iv-card-header>
      <iv-card-content>
        <p class="text-muted-foreground text-sm">Unlimited projects, custom themes and priority support.</p>
      </iv-card-content>
    </iv-card>
  `,
})
export default class CardImageDemo {}

Header divider

Users

Table goes here.

import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IvButton } from '@inlaylab/ivorie/button';
import { LucideEllipsis } from '@lucide/angular';

@Component({
  selector: 'demo-card-header-divider',
  imports: [IV_CARD_IMPORTS, IvButton, LucideEllipsis],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-sm">
      <iv-card-header class="border-b">
        <iv-card-title>Users</iv-card-title>
        <iv-card-action>
          <button ivButton size="icon-sm" variant="ghost" aria-label="More">
            <svg lucideEllipsis></svg>
          </button>
        </iv-card-action>
      </iv-card-header>
      <iv-card-content>
        <p class="text-sm">Table goes here.</p>
      </iv-card-content>
    </iv-card>
  `,
})
export default class CardHeaderDividerDemo {}

API

Every part also accepts class.

iv-card

Name Type Default Description
size 'default' | 'sm' 'default' sm reduces gap, padding and font size in all child parts. Set it only on the card.

Other parts

No inputs besides class: iv-card-header, iv-card-title, iv-card-description, iv-card-action, iv-card-content, iv-card-footer.

Accessibility

A card has no role. Use a real heading element for the title if the page outline needs one.

Notes

  • Put iv-card-action inside iv-card-header. It sits top right.
  • Make iv-card-footer a direct child of iv-card.
  • An img as first or last child gets rounded corners.
  • Add class="border-b" to iv-card-header for a divider.