Description List
The <smart-description-list> component renders a list of label/value pairs (a <dl> with <dt>/<dd> rows) with optional title, description, per-item value/action template slots, and bottom attachments/footer slots. It follows the Base + Standard + Wrapper pattern with an InjectionToken-based extension mechanism. The abstract DescriptionListBaseComponent defines the shared API — optional IDescriptionListOptions and cssClass (alias class). DescriptionListStandardComponent is a barebones placeholder concrete implementation. DescriptionListComponent is the public wrapper that renders DescriptionListStandardComponent by default and accepts a custom replacement via DESCRIPTION_LIST_STANDARD_COMPONENT_TOKEN.
Usage
<smart-description-list [options]="options()" />
<ng-template #editEmail>
<button type="button" (click)="onEdit('email')">Update</button>
</ng-template>
Components
DescriptionListComponent (<smart-description-list>)
Main wrapper component. Renders DescriptionListStandardComponent by default. When DESCRIPTION_LIST_STANDARD_COMPONENT_TOKEN is provided, renders the injected component via NgComponentOutlet.
DescriptionListStandardComponent (<smart-description-list-standard>)
Barebones placeholder concrete implementation. Renders a wrapper <div> containing an optional <h3 class="title">, optional <p class="description">, and a <dl> with one <div class="item"> per item. Each item renders a <dt> (label) and a <dd> whose content is either the static value string or the valueTpl template, optionally followed by actionTpl inside <span class="action">. Bottom slots attachmentsTpl and footerTpl render in <div class="attachments"> and <div class="footer"> respectively. The external cssClass is applied to the root wrapper. It does not include any visual styling — it exists solely as the default structural placeholder until a custom implementation is registered through the token.
DescriptionListBaseComponent (abstract)
Abstract base directive for extending custom description-list implementations. Exposes options as an InputSignal<IDescriptionListOptions | undefined> and cssClass as an InputSignal<string> (with alias class).
API
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
options | InputSignal<IDescriptionListOptions | undefined> | - | Optional configuration (title, description, items, attachments/footer slot templates) |
class | InputSignal<string> | '' | External CSS classes (alias for cssClass) |
IDescriptionListOptions
All properties are optional. The default DescriptionListStandardComponent consumes every property; a section is rendered only when its template/string is provided. Within an item, valueTpl takes precedence over value when both are set.
DESCRIPTION_LIST_STANDARD_COMPONENT_TOKEN
InjectionToken that allows replacing the default DescriptionListStandardComponent with a custom implementation. Provide a Type<DescriptionListBaseComponent> to override.
Extending the base class
import { NgTemplateOutlet } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
computed,
input,
ViewEncapsulation,
} from '@angular/core';
import {
DescriptionListBaseComponent,
DescriptionListComponent,
DESCRIPTION_LIST_STANDARD_COMPONENT_TOKEN,
IDescriptionListOptions,
} from '@smartsoft001/angular';
/**
* A custom description list built on `DescriptionListBaseComponent`.
*
* The base contributes the `options` and `class` inputs. Each item carries
* either a plain `value` or a `valueTpl` template, so an implementation that
* wants to stay compatible with the standard one projects both.
*/
@Component({
selector: 'docs-custom-description-list',
template: `
<div [class]="containerClasses()">
@if (options()?.title) {
<h3 class="docs-description-list__title">{{ options()!.title }}</h3>
}
@if (options()?.description) {
<p class="docs-description-list__description">
{{ options()!.description }}
</p>
}
<dl>
@for (item of options()?.items ?? []; track $index) {
<div class="docs-description-list__row">
<dt>{{ item.label }}</dt>
<dd>
@if (item.valueTpl) {
<ng-container [ngTemplateOutlet]="item.valueTpl" />
} @else {
{{ item.value }}
}
</dd>
</div>
}
</dl>
</div>
`,
imports: [NgTemplateOutlet],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomDescriptionListComponent extends DescriptionListBaseComponent {
// The wrapper hands inputs to NgComponentOutlet by canonical name, so the
// consumer's class arrives as `cssClass` rather than through the alias.
override cssClass = input<string>('');
containerClasses = computed(() =>
['docs-description-list', this.cssClass()].filter(Boolean).join(' '),
);
}
/**
* Registering the implementation against
* `DESCRIPTION_LIST_STANDARD_COMPONENT_TOKEN` makes every
* `<smart-description-list>` in this injector render it instead of the
* standard variation.
*/
@Component({
selector: 'docs-description-list-custom-example',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [DescriptionListComponent],
providers: [
{
provide: DESCRIPTION_LIST_STANDARD_COMPONENT_TOKEN,
useValue: CustomDescriptionListComponent,
},
],
template: `<smart-description-list [options]="options" />`,
})
export class DescriptionListCustomExampleComponent {
options: IDescriptionListOptions = {
title: 'Applicant information',
description: 'Personal details and application.',
items: [
{ label: 'Full name', value: 'Margot Foster' },
{ label: 'Application for', value: 'Backend Developer' },
{ label: 'Salary expectation', value: '$120,000' },
],
};
}
Preset
DescriptionListPresetComponent (<smart-description-list-preset>) is a styled drop-in replacement for the barebones standard component. It renders the same structure with Tailwind utility classes (every class carries the smart: prefix, with explicit smart:dark:* twins):
- Optional header (
data-role="header"): title as<h3>(text-base font-semibold text-gray-900 dark:text-white) and description as<p>(text-sm text-gray-500 dark:text-gray-400). Rendered only when title or description is set. - List (
data-role="list"): the<dl>carriesdivide-y divide-gray-200 dark:divide-gray-700; the externalcssClassis merged onto it. - Rows (
data-role="row"):grid py-3 sm:grid-cols-3 sm:gap-4with<dt>(data-role="term",text-sm font-medium text-gray-500 dark:text-gray-400) and<dd>(data-role="value",text-sm text-gray-900 dark:text-white sm:col-span-2).valueTplwins overvalue;actionTplrenders right-aligned insidedata-role="action". - Optional
attachmentsTpl(data-role="attachments") andfooterTpl(data-role="footer") render as separate sections below the list.
Because the wrapper forwards inputs canonically through NgComponentOutlet, the preset declares override cssClass = input<string>('') (dropping the inherited class alias). Register it through the token to restyle every <smart-description-list>:
No new IDescriptionListOptions fields are introduced; the preset consumes the existing API. Class recipes live in preset/preset-classes.util.ts (not exported from the barrel).
Source
The component lives in packages/shared/angular/src/lib/components/description-list and is documented for Claude Code by the angular-components-description-list skill.