Spartans get ready! v1 is coming!
We are very close to our first stable release. Expect more announcements in the coming weeks. v1 was made possible by our partner Zerops.
- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- Button Group
- Calendar
- Card
- Carousel
- Checkbox
- Collapsible
- Combobox
- Command
- Context Menu
- Data Table
- Date Picker
- Dialog
- Dropdown Menu
- Empty
- Form Field
- Hover Card
- Icon
- Input Group
- Input OTP
- Input
- Item
- Kbd
- Label
- Menubar
- Pagination
- Popover
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner (Toast)
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Toggle Group
- Tooltip
Item
A versatile component that you can use to display any content.
A simple item with title and description.
import { Component } from '@angular/core';
import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideBadgeCheck, lucideChevronRight } from '@ng-icons/lucide';
import { HlmButtonImports } from '@spartan-ng/helm/button';
import { HlmIconImports } from '@spartan-ng/helm/icon';
import { HlmItemImports } from '@spartan-ng/helm/item';
@Component({
selector: 'spartan-item-preview',
providers: [
provideIcons({
lucideBadgeCheck,
lucideChevronRight,
}),
],
imports: [HlmItemImports, HlmButtonImports, NgIcon, HlmIconImports],
template: `
<div class="flex w-full max-w-md flex-col gap-6">
<div hlmItem variant="outline">
<div hlmItemContent>
<div hlmItemTitle>Basic Item</div>
<p hlmItemDescription>A simple item with title and description.</p>
</div>
<div hlmItemActions>
<button hlmBtn variant="outline" size="sm">Action</button>
</div>
</div>
<a hlmItem variant="outline" size="sm">
<div hlmItemMedia>
<ng-icon hlm name="lucideBadgeCheck" size="20px" />
</div>
<div hlmItemContent>
<div hlmItemTitle>Your profile has been verified.</div>
</div>
<div hlmItemActions>
<ng-icon hlm name="lucideChevronRight" size="sm" />
</div>
</a>
</div>
`,
})
export class ItemPreview {}Installation
npx nx g @spartan-ng/cli:ui item
ng g @spartan-ng/cli:ui item
Usage
import { HlmItemImports } from '@spartan-ng/helm/item';<div hlmItem>
<div hlmItemHeader>Item Header</div>
<div hlmItemMedia />
<div hlmItemContent>
<div hlmItemTitle>Item</div>
<p hlmItemDescription>Item</div>
</p hlmItemContent>
<div hlmItemActions />
<div hlmItemFooter>Item Footer</div>
</div>Item vs Field
Use hlmField if you need to display a form input such as a checkbox, input, radio, or select. If you only need to display content such as a title, description, and actions, use hlmItem .
Variants
Standard styling with subtle background and borders.
Outlined style with clear borders and transparent background.
Subdued appearance with muted colors for secondary content.
import { Component } from '@angular/core';
import { HlmButtonImports } from '@spartan-ng/helm/button';
import { HlmItemImports } from '@spartan-ng/helm/item';
@Component({
selector: 'spartan-item-variants-preview',
imports: [HlmItemImports, HlmButtonImports],
host: {
class: 'flex w-full max-w-md flex-col gap-6',
},
template: `
<div hlmItem>
<div hlmItemContent>
<div hlmItemTitle>Default Variant</div>
<p hlmItemDescription>Standard styling with subtle background and borders.</p>
</div>
<div hlmItemActions>
<button hlmBtn variant="outline" size="sm">Open</button>
</div>
</div>
<div hlmItem variant="outline">
<div hlmItemContent>
<div hlmItemTitle>Outline Variant</div>
<p hlmItemDescription>Outlined style with clear borders and transparent background.</p>
</div>
<div hlmItemActions>
<button hlmBtn variant="outline" size="sm">Open</button>
</div>
</div>
<div hlmItem variant="muted">
<div hlmItemContent>
<div hlmItemTitle>Muted Variant</div>
<p hlmItemDescription>Subdued appearance with muted colors for secondary content.</p>
</div>
<div hlmItemActions>
<button hlmBtn variant="outline" size="sm">Open</button>
</div>
</div>
`,
})
export class ItemVariantsPreview {}Size
The hlmItem component has different sizes for different use cases. For example, you can use the sm size for a compact item or the default size for a standard item.
A simple item with title and description.
import { Component } from '@angular/core';
import { provideIcons } from '@ng-icons/core';
import { lucideBadgeCheck, lucideChevronRight } from '@ng-icons/lucide';
import { HlmButtonImports } from '@spartan-ng/helm/button';
import { HlmIconImports } from '@spartan-ng/helm/icon';
import { HlmItemImports } from '@spartan-ng/helm/item';
@Component({
selector: 'spartan-item-size-preview',
imports: [HlmItemImports, HlmButtonImports, HlmIconImports],
providers: [
provideIcons({
lucideBadgeCheck,
lucideChevronRight,
}),
],
host: {
class: 'flex w-full max-w-md flex-col gap-6',
},
template: `
<div hlmItem variant="outline">
<div hlmItemContent>
<div hlmItemTitle>Basic Item</div>
<p hlmItemDescription>A simple item with title and description.</p>
</div>
<div hlmItemActions>
<button hlmBtn variant="outline" size="sm">Action</button>
</div>
</div>
<a hlmItem variant="outline" size="sm" href="#">
<div hlmItemMedia>
<ng-icon hlm name="lucideBadgeCheck" size="20px" />
</div>
<div hlmItemContent>
<div hlmItemTitle>Your profile has been verified.</div>
</div>
<div hlmItemActions>
<ng-icon hlm name="lucideChevronRight" size="sm" />
</div>
</a>
`,
})
export class ItemSizePreview {}Icon
New login detected from unknown device.
import { Component } from '@angular/core';
import { provideIcons } from '@ng-icons/core';
import { lucideShieldAlert } from '@ng-icons/lucide';
import { HlmButtonImports } from '@spartan-ng/helm/button';
import { HlmIconImports } from '@spartan-ng/helm/icon';
import { HlmItemImports } from '@spartan-ng/helm/item';
@Component({
selector: 'spartan-item-icon-preview',
imports: [HlmItemImports, HlmButtonImports, HlmIconImports],
providers: [
provideIcons({
lucideShieldAlert,
}),
],
host: {
class: 'flex w-full max-w-lg flex-col gap-6',
},
template: `
<div hlmItem variant="outline">
<div hlmItemMedia variant="icon">
<ng-icon hlm name="lucideShieldAlert" size="sm" />
</div>
<div hlmItemContent>
<div hlmItemTitle>Security Alert</div>
<p hlmItemDescription>New login detected from unknown device.</p>
</div>
<div hlmItemActions>
<button hlmBtn size="sm" variant="outline">Review</button>
</div>
</div>
`,
})
export class ItemIconPreview {}Avatar
Last seen 5 months ago
Invite your team to collaborate on this project.
import { Component } from '@angular/core';
import { provideIcons } from '@ng-icons/core';
import { lucidePlus } from '@ng-icons/lucide';
import { HlmAvatarImports } from '@spartan-ng/helm/avatar';
import { HlmButtonImports } from '@spartan-ng/helm/button';
import { HlmIconImports } from '@spartan-ng/helm/icon';
import { HlmItemImports } from '@spartan-ng/helm/item';
@Component({
selector: 'spartan-item-avatar-preview',
imports: [HlmItemImports, HlmButtonImports, HlmAvatarImports, HlmIconImports],
providers: [
provideIcons({
lucidePlus,
}),
],
host: {
class: 'flex w-full max-w-lg flex-col gap-6',
},
template: `
<!-- Item 1: Evil Rabbit -->
<div hlmItem variant="outline">
<div hlmItemMedia>
<hlm-avatar class="size-10">
<img hlmAvatarImage src="https://github.com/evilrabbit.png" alt="Evil Rabbit" />
<span hlmAvatarFallback>ER</span>
</hlm-avatar>
</div>
<div hlmItemContent>
<div hlmItemTitle>Evil Rabbit</div>
<p hlmItemDescription>Last seen 5 months ago</p>
</div>
<div hlmItemActions>
<button hlmBtn size="icon-sm" variant="outline" class="rounded-full" aria-label="Invite">
<ng-icon hlm name="lucidePlus" />
</button>
</div>
</div>
<!-- Item 2: No Team Members -->
<div hlmItem variant="outline">
<div hlmItemMedia>
<div
class="*:data-[slot=avatar]:ring-background flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:grayscale"
>
<hlm-avatar class="hidden sm:flex">
<img hlmAvatarImage src="https://github.com/spartan-ng.png" alt="@spartan-ng" />
<span hlmAvatarFallback>CN</span>
</hlm-avatar>
<hlm-avatar class="hidden sm:flex">
<img hlmAvatarImage src="https://github.com/maxleiter.png" alt="@maxleiter" />
<span hlmAvatarFallback>LR</span>
</hlm-avatar>
<hlm-avatar>
<img hlmAvatarImage src="https://github.com/evilrabbit.png" alt="@evilrabbit" />
<span hlmAvatarFallback>ER</span>
</hlm-avatar>
</div>
</div>
<div hlmItemContent>
<div hlmItemTitle>No Team Members</div>
<p hlmItemDescription>Invite your team to collaborate on this project.</p>
</div>
<div hlmItemActions>
<button hlmBtn size="sm" variant="outline">Invite</button>
</div>
</div>
`,
})
export class ItemAvatarPreview {}Image
import { Component } from '@angular/core';
import { HlmItemImports } from '@spartan-ng/helm/item';
@Component({
selector: 'spartan-item-image-preview',
imports: [HlmItemImports],
host: {
class: 'flex w-full max-w-md flex-col gap-6',
},
template: `
<div hlmItemGroup class="gap-4">
@for (song of _songs; track song.title) {
<a hlmItem variant="outline" role="listitem" href="#">
<div hlmItemMedia variant="image">
<img
[src]="'https://avatar.vercel.sh/' + song.title"
[alt]="song.title"
width="32"
height="32"
class="object-cover grayscale"
/>
</div>
<div hlmItemContent>
<div hlmItemTitle class="line-clamp-1">
{{ song.title }} -
<span class="text-muted-foreground">{{ song.album }}</span>
</div>
<p hlmItemDescription>{{ song.artist }}</p>
</div>
<div hlmItemContent class="flex-none text-center">
<p hlmItemDescription>{{ song.duration }}</p>
</div>
</a>
}
</div>
`,
})
export class ItemImagePreview {
protected readonly _songs = [
{
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
spartan@ng.com
maxleiter@vercel.com
evilrabbit@vercel.com
import { Component } from '@angular/core';
import { provideIcons } from '@ng-icons/core';
import { lucidePlus } from '@ng-icons/lucide';
import { HlmAvatarImports } from '@spartan-ng/helm/avatar';
import { HlmButtonImports } from '@spartan-ng/helm/button';
import { HlmIconImports } from '@spartan-ng/helm/icon';
import { HlmItemImports } from '@spartan-ng/helm/item';
@Component({
selector: 'spartan-item-group-preview',
imports: [HlmItemImports, HlmButtonImports, HlmIconImports, HlmAvatarImports],
providers: [
provideIcons({
lucidePlus,
}),
],
host: {
class: 'flex w-full max-w-md flex-col gap-6',
},
template: `
<div hlmItemGroup>
@for (person of _people; track person.username; let last = $last) {
<div hlmItem>
<div hlmItemMedia>
<hlm-avatar>
<img hlmAvatarImage [src]="person.avatar" [alt]="person.username" class="grayscale" />
<span hlmAvatarFallback>{{ person.username.charAt(0).toUpperCase() }}</span>
</hlm-avatar>
</div>
<div hlmItemContent class="gap-1">
<div hlmItemTitle>{{ person.username }}</div>
<p hlmItemDescription>{{ person.email }}</p>
</div>
<div hlmItemActions>
<button hlmBtn variant="ghost" size="icon" class="rounded-full">
<ng-icon hlm name="lucidePlus" />
</button>
</div>
</div>
@if (!last) {
<div hlmItemSeparator></div>
}
}
</div>
`,
})
export class ItemGroupPreview {
protected readonly _people = [
{
username: 'spartan-ng',
avatar: 'https://github.com/spartan-ng.png',
email: 'spartan@ng.com',
},
{
username: 'maxleiter',
avatar: 'https://github.com/maxleiter.png',
email: 'maxleiter@vercel.com',
},
{
username: 'evilrabbit',
avatar: 'https://github.com/evilrabbit.png',
email: 'evilrabbit@vercel.com',
},
];
}
``;Header
Everyday tasks and UI generation.
Advanced thinking or reasoning.
Open Source model for everyone.
import { Component } from '@angular/core';
import { HlmItemImports } from '@spartan-ng/helm/item';
@Component({
selector: 'spartan-item-header-preview',
imports: [HlmItemImports],
host: {
class: 'flex w-full max-w-xl flex-col gap-6',
},
template: `
<div hlmItemGroup class="grid grid-cols-3 gap-4">
@for (model of _models; track model.name) {
<div hlmItem variant="outline">
<div hlmItemHeader>
<img
[src]="model.image"
[alt]="model.name"
width="128"
height="128"
class="aspect-square w-full rounded-sm object-cover"
/>
</div>
<div hlmItemContent>
<div hlmItemTitle>{{ model.name }}</div>
<p hlmItemDescription>{{ model.description }}</p>
</div>
</div>
}
</div>
`,
})
export class ItemHeaderPreview {
protected readonly _models = [
{
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',
},
{
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',
},
{
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',
},
];
}Link
To render an item as a link, use a anchor element. The hover and focus states will be applied to the anchor element.
import { Component } from '@angular/core';
import { provideIcons } from '@ng-icons/core';
import { lucideChevronRight, lucideExternalLink } from '@ng-icons/lucide';
import { HlmIconImports } from '@spartan-ng/helm/icon';
import { HlmItemImports } from '@spartan-ng/helm/item';
@Component({
selector: 'spartan-item-link-preview',
imports: [HlmItemImports, HlmIconImports],
providers: [
provideIcons({
lucideChevronRight,
lucideExternalLink,
}),
],
host: {
class: 'flex w-full max-w-md flex-col gap-6',
},
template: `
<a hlmItem href="#">
<div hlmItemContent>
<div hlmItemTitle>Visit our documentation</div>
<p hlmItemDescription>Learn how to get started with our components.</p>
</div>
<div hlmItemActions>
<ng-icon hlm name="lucideChevronRight" size="sm" />
</div>
</a>
<a hlmItem variant="outline" href="#" target="_blank" rel="noopener noreferrer">
<div hlmItemContent>
<div hlmItemTitle>External resource</div>
<p hlmItemDescription>Opens in a new tab with security attributes.</p>
</div>
<div hlmItemActions>
<ng-icon hlm name="lucideExternalLink" size="sm" />
</div>
</a>
`,
})
export class ItemLinkPreview {}Dropdown
import { Component } from '@angular/core';
import { provideIcons } from '@ng-icons/core';
import { lucideChevronDown } from '@ng-icons/lucide';
import { BrnMenuImports } from '@spartan-ng/brain/menu';
import { HlmAvatarImports } from '@spartan-ng/helm/avatar';
import { HlmButtonImports } from '@spartan-ng/helm/button';
import { HlmIconImports } from '@spartan-ng/helm/icon';
import { HlmItemImports } from '@spartan-ng/helm/item';
import { HlmMenuImports } from '@spartan-ng/helm/menu';
@Component({
selector: 'spartan-item-dropdown-preview',
imports: [HlmItemImports, HlmButtonImports, HlmAvatarImports, HlmIconImports, BrnMenuImports, HlmMenuImports],
providers: [
provideIcons({
lucideChevronDown,
}),
],
host: {
class: 'flex min-h-64 w-full max-w-md flex-col items-center gap-6',
},
template: `
<button hlmBtn variant="outline" size="sm" [brnMenuTriggerFor]="people" class="w-fit" align="end">
Select
<ng-icon hlm name="lucideChevronDown" />
</button>
<ng-template #people>
<hlm-menu class="w-72 [--radius:0.65rem]">
@for (person of _people; track person.email) {
<div hlmMenuItem class="p-0">
<div hlmItem size="sm" class="w-full p-2">
<div hlmItemMedia>
<hlm-avatar class="size-8">
<img hlmAvatarImage [src]="person.avatar" [alt]="person.username" class="grayscale" />
<span hlmAvatarFallback>
{{ person.username.charAt(0).toUpperCase() }}
</span>
</hlm-avatar>
</div>
<div hlmItemContent class="gap-0.5">
<div hlmItemTitle>{{ person.username }}</div>
<p hlmItemDescription>{{ person.email }}</p>
</div>
</div>
</div>
}
</hlm-menu>
</ng-template>
`,
})
export class ItemDropdownPreview {
protected readonly _people = [
{
username: 'spartan-ng',
avatar: 'https://github.com/spartan-ng.png',
email: 'spartan@ng.com',
},
{
username: 'maxleiter',
avatar: 'https://github.com/maxleiter.png',
email: 'maxleiter@vercel.com',
},
{
username: 'evilrabbit',
avatar: 'https://github.com/evilrabbit.png',
email: 'evilrabbit@vercel.com',
},
];
}Helm API
HlmItemActions
Selector: div[hlmItemActions]
Inputs
| Prop | Type | Default | Description |
|---|---|---|---|
| class | ClassValue | - | - |
HlmItemContent
Selector: div[hlmItemContent]
Inputs
| Prop | Type | Default | Description |
|---|---|---|---|
| class | ClassValue | - | - |
HlmItemDescription
Selector: p[hlmItemDescription]
Inputs
| Prop | Type | Default | Description |
|---|---|---|---|
| class | ClassValue | - | - |
HlmItemFooter
Selector: div[hlmItemFooter]
Inputs
| Prop | Type | Default | Description |
|---|---|---|---|
| class | ClassValue | - | - |
HlmItemGroup
Selector: div[hlmItemGroup]
Inputs
| Prop | Type | Default | Description |
|---|---|---|---|
| class | ClassValue | - | - |
HlmItemHeader
Selector: div[hlmItemHeader]
Inputs
| Prop | Type | Default | Description |
|---|---|---|---|
| class | ClassValue | - | - |
HlmItemMedia
Selector: div[hlmItemMedia]
Inputs
| Prop | Type | Default | Description |
|---|---|---|---|
| class | ClassValue | - | - |
| variant | ItemMediaVariants['variant'] | this._config.variant | - |
HlmItemSeparator
Selector: div[hlmItemSeparator]
Inputs
| Prop | Type | Default | Description |
|---|---|---|---|
| class | ClassValue | - | - |
HlmItemTitle
Selector: div[hlmItemTitle]
Inputs
| Prop | Type | Default | Description |
|---|---|---|---|
| class | ClassValue | - | - |
HlmItem
Selector: div[hlmItem], a[hlmItem]
Inputs
| Prop | Type | Default | Description |
|---|---|---|---|
| class | ClassValue | - | - |
| variant | ItemVariants['variant'] | this._config.variant | - |
| size | ItemVariants['size'] | this._config.size | - |