item

A versatile component for displaying content with media, title, description, and actions.

PreviousNext
Basic ItemA simple item with title and description.Your profile has been verified.
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideBadgeCheck, lucideChevronRight } from '@ng-icons/lucide';

import { ZardButtonComponent } from '@/shared/components/button/button.component';
import { ZardItemImports } from '@/shared/components/item/item.imports';

@Component({
  selector: 'z-demo-item-preview',
  imports: [ZardButtonComponent, NgIcon, ...ZardItemImports],
  template: `
    <div class="flex w-full min-w-md flex-col gap-6">
      <z-item zVariant="outline">
        <z-item-content>
          <z-item-title>Basic Item</z-item-title>
          <z-item-description>A simple item with title and description.</z-item-description>
        </z-item-content>
        <z-item-actions>
          <button type="button" z-button zType="outline" zSize="sm">Action</button>
        </z-item-actions>
      </z-item>

      <a z-item href="#" zVariant="outline" zSize="sm">
        <z-item-media>
          <ng-icon name="lucideBadgeCheck" size="1.25rem" />
        </z-item-media>
        <z-item-content>
          <z-item-title>Your profile has been verified.</z-item-title>
        </z-item-content>
        <z-item-actions>
          <ng-icon name="lucideChevronRight" size="1rem" />
        </z-item-actions>
      </a>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  viewProviders: [provideIcons({ lucideBadgeCheck, lucideChevronRight })],
})
export class ZardDemoItemPreviewComponent {}

Installation

Copy
npx zard-cli@latest add item

Usage

import { ZardItemImports } from '@/shared/components/item/item.imports';
Copy
<z-item zVariant="outline">
  <z-item-content>
    <z-item-title>Title</z-item-title>
    <z-item-description>Description</z-item-description>
  </z-item-content>
</z-item>
Copy

Examples

variant

zVariant on z-item switches the container surface between default (transparent), outline (a visible border) and muted (a tinted background); every row here also sets z-item-media's zVariant to "icon".
Default VariantTransparent background with no border.Outline VariantOutlined style with a visible border.Muted VariantMuted background for secondary content.
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideInbox } from '@ng-icons/lucide';

import { ZardItemImports } from '@/shared/components/item/item.imports';

@Component({
  selector: 'z-demo-item-variant',
  imports: [NgIcon, ...ZardItemImports],
  template: `
    <div class="flex w-full min-w-md flex-col gap-6">
      <z-item>
        <z-item-media zVariant="icon">
          <ng-icon name="lucideInbox" />
        </z-item-media>
        <z-item-content>
          <z-item-title>Default Variant</z-item-title>
          <z-item-description>Transparent background with no border.</z-item-description>
        </z-item-content>
      </z-item>
      <z-item zVariant="outline">
        <z-item-media zVariant="icon">
          <ng-icon name="lucideInbox" />
        </z-item-media>
        <z-item-content>
          <z-item-title>Outline Variant</z-item-title>
          <z-item-description>Outlined style with a visible border.</z-item-description>
        </z-item-content>
      </z-item>
      <z-item zVariant="muted">
        <z-item-media zVariant="icon">
          <ng-icon name="lucideInbox" />
        </z-item-media>
        <z-item-content>
          <z-item-title>Muted Variant</z-item-title>
          <z-item-description>Muted background for secondary content.</z-item-description>
        </z-item-content>
      </z-item>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  viewProviders: [provideIcons({ lucideInbox })],
})
export class ZardDemoItemVariantComponent {}

size

zSize on z-item sets the density: default and sm share the same padding, xs switches to the compact scale used inside menus and tightens the gap between title and description.
Default SizeThe standard size for most use cases.Small SizeA compact size for dense layouts.Extra Small SizeThe most compact size available.
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideInbox } from '@ng-icons/lucide';

import { ZardItemImports } from '@/shared/components/item/item.imports';

@Component({
  selector: 'z-demo-item-size',
  imports: [NgIcon, ...ZardItemImports],
  template: `
    <div class="flex w-full min-w-md flex-col gap-6">
      <z-item zVariant="outline">
        <z-item-media zVariant="icon">
          <ng-icon name="lucideInbox" />
        </z-item-media>
        <z-item-content>
          <z-item-title>Default Size</z-item-title>
          <z-item-description>The standard size for most use cases.</z-item-description>
        </z-item-content>
      </z-item>
      <z-item zVariant="outline" zSize="sm">
        <z-item-media zVariant="icon">
          <ng-icon name="lucideInbox" />
        </z-item-media>
        <z-item-content>
          <z-item-title>Small Size</z-item-title>
          <z-item-description>A compact size for dense layouts.</z-item-description>
        </z-item-content>
      </z-item>
      <z-item zVariant="outline" zSize="xs">
        <z-item-media zVariant="icon">
          <ng-icon name="lucideInbox" />
        </z-item-media>
        <z-item-content>
          <z-item-title>Extra Small Size</z-item-title>
          <z-item-description>The most compact size available.</z-item-description>
        </z-item-content>
      </z-item>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  viewProviders: [provideIcons({ lucideInbox })],
})
export class ZardDemoItemSizeComponent {}

icon

z-item-media's own zVariant switches between default, icon and image treatments; set to "icon" here, it sizes and aligns a projected ng-icon at the leading edge of the item.
Security AlertNew login detected from unknown device.
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideShieldAlert } from '@ng-icons/lucide';

import { ZardButtonComponent } from '@/shared/components/button/button.component';
import { ZardItemImports } from '@/shared/components/item/item.imports';

@Component({
  selector: 'z-demo-item-icon',
  imports: [ZardButtonComponent, NgIcon, ...ZardItemImports],
  template: `
    <div class="flex w-full min-w-lg flex-col gap-6">
      <z-item zVariant="outline">
        <z-item-media zVariant="icon">
          <ng-icon name="lucideShieldAlert" />
        </z-item-media>
        <z-item-content>
          <z-item-title>Security Alert</z-item-title>
          <z-item-description>New login detected from unknown device.</z-item-description>
        </z-item-content>
        <z-item-actions>
          <button type="button" z-button zType="outline" zSize="sm">Review</button>
        </z-item-actions>
      </z-item>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  viewProviders: [provideIcons({ lucideShieldAlert })],
})
export class ZardDemoItemIconComponent {}

avatar

There is no dedicated avatar media variant — project a real z-avatar or z-avatar-group into z-item-media's default variant and size it directly with a class on the avatar.
ER Evil RabbitLast seen 5 months ago ZU @zardui SR @srizzon LG @luizgomessNo Team MembersInvite your team to collaborate on this project.
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucidePlus } from '@ng-icons/lucide';

import { ZardAvatarComponent, ZardAvatarGroupComponent } from '@/shared/components/avatar';
import { ZardButtonComponent } from '@/shared/components/button/button.component';
import { ZardItemImports } from '@/shared/components/item/item.imports';

@Component({
  selector: 'z-demo-item-avatar',
  imports: [ZardAvatarComponent, ZardAvatarGroupComponent, ZardButtonComponent, NgIcon, ...ZardItemImports],
  template: `
    <div class="flex w-full min-w-lg flex-col gap-6">
      <z-item zVariant="outline">
        <z-item-media>
          <z-avatar zSrc="https://github.com/evilrabbit.png" zFallback="ER" class="size-10" />
        </z-item-media>
        <z-item-content>
          <z-item-title>Evil Rabbit</z-item-title>
          <z-item-description>Last seen 5 months ago</z-item-description>
        </z-item-content>
        <z-item-actions>
          <button type="button" z-button zType="outline" zSize="icon-sm" zShape="circle" aria-label="Invite">
            <ng-icon name="lucidePlus" />
          </button>
        </z-item-actions>
      </z-item>

      <z-item zVariant="outline">
        <z-item-media>
          <z-avatar-group>
            <z-avatar zSrc="https://github.com/zard-ui.png" zAlt="@zardui" zFallback="ZU" class="grayscale" />
            <z-avatar zSrc="https://github.com/srizzon.png" zAlt="@srizzon" zFallback="SR" class="grayscale" />
            <z-avatar zSrc="https://github.com/Luizgomess.png" zAlt="@luizgomess" zFallback="LG" class="grayscale" />
          </z-avatar-group>
        </z-item-media>
        <z-item-content>
          <z-item-title>No Team Members</z-item-title>
          <z-item-description>Invite your team to collaborate on this project.</z-item-description>
        </z-item-content>
        <z-item-actions>
          <button type="button" z-button zType="outline" zSize="sm">Invite</button>
        </z-item-actions>
      </z-item>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  viewProviders: [provideIcons({ lucidePlus })],
})
export class ZardDemoItemAvatarComponent {}

image

z-item-media's zVariant="image" clips a projected image (NgOptimizedImage here) to a fixed square that scales with the item's zSize.
import { NgOptimizedImage } from '@angular/common';
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { ZardItemImports } from '@/shared/components/item/item.imports';

interface Song {
  title: string;
  artist: string;
  album: string;
  duration: string;
}

@Component({
  selector: 'z-demo-item-image',
  imports: [NgOptimizedImage, ...ZardItemImports],
  template: `
    <div class="flex w-full min-w-md flex-col gap-6">
      <z-item-group class="gap-4">
        @for (song of music; track song.title) {
          <a z-item href="#" zVariant="outline" role="listitem">
            <z-item-media zVariant="image">
              <img
                [ngSrc]="'https://avatar.vercel.sh/' + song.title"
                [alt]="song.title"
                width="120"
                height="120"
                class="grayscale"
              />
            </z-item-media>
            <z-item-content>
              <z-item-title class="line-clamp-1">
                {{ song.title }} -
                <span class="text-muted-foreground">{{ song.album }}</span>
              </z-item-title>
              <z-item-description>{{ song.artist }}</z-item-description>
            </z-item-content>
            <z-item-content class="flex-none text-center">
              <z-item-description>{{ song.duration }}</z-item-description>
            </z-item-content>
          </a>
        }
      </z-item-group>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoItemImageComponent {
  protected readonly music: Song[] = [
    { title: 'Midnight City Lights', artist: 'Neon Dreams', album: 'Electric Nights', duration: '3:45' },
    { title: 'Coffee Shop Conversations', artist: 'The Morning Brew', album: 'Urban Stories', duration: '4:05' },
    { title: 'Digital Rain', artist: 'Cyber Symphony', album: 'Binary Beats', duration: '3:30' },
  ];
}

group

z-item-group (role="list") wraps several z-item rows and applies consistent spacing between them.
Z zarduizardui@example.com S srizzonsrizzon@example.com L luizgomessluizgomess@example.com
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucidePlus } from '@ng-icons/lucide';

import { ZardAvatarComponent } from '@/shared/components/avatar';
import { ZardButtonComponent } from '@/shared/components/button/button.component';
import { ZardItemImports } from '@/shared/components/item/item.imports';

interface Person {
  username: string;
  avatar: string;
  email: string;
}

@Component({
  selector: 'z-demo-item-group',
  imports: [ZardAvatarComponent, ZardButtonComponent, NgIcon, ...ZardItemImports],
  template: `
    <z-item-group class="min-w-sm">
      @for (person of people; track person.username) {
        <z-item zVariant="outline">
          <z-item-media>
            <z-avatar [zSrc]="person.avatar" [zFallback]="person.username.charAt(0).toUpperCase()" class="grayscale" />
          </z-item-media>
          <z-item-content class="gap-1">
            <z-item-title>{{ person.username }}</z-item-title>
            <z-item-description>{{ person.email }}</z-item-description>
          </z-item-content>
          <z-item-actions>
            <button type="button" z-button zType="ghost" zSize="icon-sm" zShape="circle">
              <ng-icon name="lucidePlus" />
            </button>
          </z-item-actions>
        </z-item>
      }
    </z-item-group>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  viewProviders: [provideIcons({ lucidePlus })],
})
export class ZardDemoItemGroupComponent {
  protected readonly people: Person[] = [
    { username: 'zardui', avatar: 'https://github.com/zard-ui.png', email: 'zardui@example.com' },
    { username: 'srizzon', avatar: 'https://github.com/srizzon.png', email: 'srizzon@example.com' },
    { username: 'luizgomess', avatar: 'https://github.com/Luizgomess.png', email: 'luizgomess@example.com' },
  ];
}

header

z-item-header renders a full-width row above z-item-content and z-item-footer renders the matching row below it — shown here with an image header and a price/action footer.
v0-1.5-smv0-1.5-smEveryday tasks and UI generation.Freev0-1.5-lgv0-1.5-lgAdvanced thinking or reasoning.Prov0-2.0-miniv0-2.0-miniOpen Source model for everyone.Free
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { ZardBadgeComponent } from '@/shared/components/badge';
import { ZardButtonComponent } from '@/shared/components/button/button.component';
import { ZardItemImports } from '@/shared/components/item/item.imports';

interface Model {
  name: string;
  description: string;
  image: string;
  price: string;
}

@Component({
  selector: 'z-demo-item-header',
  imports: [ZardBadgeComponent, ZardButtonComponent, ...ZardItemImports],
  template: `
    <div class="flex w-full min-w-xl flex-col gap-6">
      <z-item-group class="grid grid-cols-3 gap-4">
        @for (model of models; track model.name) {
          <z-item zVariant="outline">
            <z-item-header>
              <img [src]="model.image" [alt]="model.name" class="aspect-square w-full rounded-sm object-cover" />
            </z-item-header>
            <z-item-content>
              <z-item-title>{{ model.name }}</z-item-title>
              <z-item-description>{{ model.description }}</z-item-description>
            </z-item-content>
            <z-item-footer>
              <z-badge zType="secondary">{{ model.price }}</z-badge>
              <button type="button" z-button zType="outline" zSize="sm">Try it</button>
            </z-item-footer>
          </z-item>
        }
      </z-item-group>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ZardDemoItemHeaderComponent {
  protected readonly models: Model[] = [
    {
      name: 'v0-1.5-sm',
      description: 'Everyday tasks and UI generation.',
      image: 'https://images.unsplash.com/photo-1650804068570-7fb2e3dbf888?q=80&w=640&auto=format&fit=crop',
      price: 'Free',
    },
    {
      name: 'v0-1.5-lg',
      description: 'Advanced thinking or reasoning.',
      image: 'https://images.unsplash.com/photo-1610280777472-54133d004c8c?q=80&w=640&auto=format&fit=crop',
      price: 'Pro',
    },
    {
      name: 'v0-2.0-mini',
      description: 'Open Source model for everyone.',
      image: 'https://images.unsplash.com/photo-1602146057681-08560aee8cde?q=80&w=640&auto=format&fit=crop',
      price: 'Free',
    },
  ];
}

link

Render the item as a real anchor with a[z-item]: bind [routerLink] for in-app navigation through the Angular Router, or pass a plain href with target/rel for an external destination.
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { RouterLink } from '@angular/router';

import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideChevronRight, lucideExternalLink } from '@ng-icons/lucide';

import { ZardItemImports } from '@/shared/components/item/item.imports';

@Component({
  selector: 'z-demo-item-link',
  imports: [NgIcon, RouterLink, ...ZardItemImports],
  template: `
    <div class="flex w-full min-w-md flex-col gap-4">
      <a z-item [routerLink]="['/docs/introduction']">
        <z-item-content>
          <z-item-title>Visit our documentation</z-item-title>
          <z-item-description>Learn how to get started with our components.</z-item-description>
        </z-item-content>
        <z-item-actions>
          <ng-icon name="lucideChevronRight" size="1rem" />
        </z-item-actions>
      </a>

      <a z-item href="https://github.com/zard-ui/zardui" zVariant="outline" target="_blank" rel="noopener noreferrer">
        <z-item-content>
          <z-item-title>External resource</z-item-title>
          <z-item-description>Opens in a new tab with security attributes.</z-item-description>
        </z-item-content>
        <z-item-actions>
          <ng-icon name="lucideExternalLink" size="1rem" />
        </z-item-actions>
      </a>
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  viewProviders: [provideIcons({ lucideChevronRight, lucideExternalLink })],
})
export class ZardDemoItemLinkComponent {}

dropdown

Compose z-item at zSize="xs" (the compact scale) inside a real z-dropdown-menu-item to give each menu option its own media/content row.
import { ChangeDetectionStrategy, Component } from '@angular/core';

import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideChevronDown } from '@ng-icons/lucide';

import { ZardAvatarComponent } from '@/shared/components/avatar';
import { ZardButtonComponent } from '@/shared/components/button/button.component';
import { ZardDropdownImports } from '@/shared/components/dropdown/dropdown.imports';
import { ZardItemImports } from '@/shared/components/item/item.imports';

interface Person {
  username: string;
  avatar: string;
  email: string;
}

@Component({
  selector: 'z-demo-item-dropdown',
  imports: [ZardAvatarComponent, ZardButtonComponent, NgIcon, ...ZardDropdownImports, ...ZardItemImports],
  template: `
    <button type="button" z-button zType="outline" z-dropdown [zDropdownMenu]="menu">
      Select
      <ng-icon name="lucideChevronDown" />
    </button>

    <z-dropdown-menu-content #menu="zDropdownMenuContent" class="w-56">
      @for (person of people; track person.username) {
        <z-dropdown-menu-item>
          <z-item zSize="xs" class="w-full p-2">
            <z-item-media>
              <z-avatar
                [zSrc]="person.avatar"
                [zFallback]="person.username.charAt(0).toUpperCase()"
                class="size-7 grayscale"
              />
            </z-item-media>
            <z-item-content class="gap-0">
              <z-item-title>{{ person.username }}</z-item-title>
              <z-item-description class="leading-none">{{ person.email }}</z-item-description>
            </z-item-content>
          </z-item>
        </z-dropdown-menu-item>
      }
    </z-dropdown-menu-content>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  viewProviders: [provideIcons({ lucideChevronDown })],
})
export class ZardDemoItemDropdownComponent {
  protected readonly people: Person[] = [
    { username: 'zardui', avatar: 'https://github.com/zard-ui.png', email: 'zardui@example.com' },
    { username: 'srizzon', avatar: 'https://github.com/srizzon.png', email: 'srizzon@example.com' },
    { username: 'luizgomess', avatar: 'https://github.com/Luizgomess.png', email: 'luizgomess@example.com' },
  ];
}

API Reference

z-itemComponent

Container for an entry composed of media, content, and actions.

PropertyDescriptionTypeDefault
[zVariant] Visual style of the item. default | outline | muted default
[zSize] Padding and density. default | sm | xs default
[class] Override or extend default classes. ClassValue -

z-item-groupComponent

Wrapper around multiple items with consistent spacing.

PropertyDescriptionTypeDefault
[class] Override or extend default classes. ClassValue -

z-item-separatorComponent

Horizontal separator rendered between items in a group.

PropertyDescriptionTypeDefault
[class] Override or extend default classes. ClassValue -

z-item-mediaComponent

Slot for an icon, image, or custom media at the leading edge of the item.

PropertyDescriptionTypeDefault
[zVariant] Media presentation. default | icon | image default
[class] Override or extend default classes. ClassValue -

z-item-contentComponent

Main text/content area; usually wraps title and description.

PropertyDescriptionTypeDefault
[class] Override or extend default classes. ClassValue -

z-item-titleComponent

Primary heading for the item.

PropertyDescriptionTypeDefault
[class] Override or extend default classes. ClassValue -

z-item-descriptionComponent

Supporting copy below the title.

PropertyDescriptionTypeDefault
[class] Override or extend default classes. ClassValue -

z-item-actionsComponent

Container for trailing buttons or controls.

PropertyDescriptionTypeDefault
[class] Override or extend default classes. ClassValue -

z-item-headerComponent

Optional header row rendered at the top of the item.

PropertyDescriptionTypeDefault
[class] Override or extend default classes. ClassValue -

z-item-footerComponent

Optional footer row rendered at the bottom of the item.

PropertyDescriptionTypeDefault
[class] Override or extend default classes. ClassValue -
github iconwhatsapp icondiscord iconX icon

Made with ❤ in Brazil. Open source and available on GitHub .