ListContainer
The <smart-list-container> component is a presentational layout wrapper that groups list items with a semantic role="list". It follows the Base + Standard + Wrapper pattern with an InjectionToken-based extension mechanism. The abstract ListContainerBaseComponent defines the shared API — optional IListContainerOptions and cssClass (alias class). ListContainerStandardComponent is a barebones placeholder concrete implementation that projects content via <ng-content /> inside a role="list" div with an optional data-variant attribute. ListContainerComponent is the public wrapper that renders ListContainerStandardComponent by default and accepts a custom replacement via LIST_CONTAINER_STANDARD_COMPONENT_TOKEN.
Usage
<smart-list-container [options]="options">
@for (notification of notifications; track notification.id) {
<div role="listitem">
<p>{{ notification.text }}</p>
<small>{{ notification.time }}</small>
</div>
}
</smart-list-container>
Components
ListContainerComponent (<smart-list-container>)
Main wrapper component. Renders ListContainerStandardComponent by default. When LIST_CONTAINER_STANDARD_COMPONENT_TOKEN is provided, renders the injected component via NgComponentOutlet. Supports content projection through <ng-content /> in the default branch, so children placed inside <smart-list-container> are rendered inside the standard list container.
ListContainerStandardComponent (<smart-list-container-standard>)
Barebones placeholder concrete implementation. Renders a <div role="list"> that:
- exposes the variant value via
data-variant(omitted whenoptionsis not provided), - applies the external
cssClassdirectly on the host div, - projects all children via
<ng-content />.
It does not include Tailwind UI styling — it exists solely as the default structural placeholder until a custom implementation is registered through the token.
ListContainerBaseComponent (abstract)
Abstract base directive for extending custom list container implementations. Exposes options as an InputSignal<IListContainerOptions | undefined> and cssClass as an InputSignal<string> (with alias class). Has no outputs or methods.
API
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
options | InputSignal<IListContainerOptions | undefined> | - | Optional configuration (variant, fullWidthOnMobile) |
class | InputSignal<string> | '' | External CSS classes (alias for cssClass) |
IListContainerOptions
The standard component only consumes variant (placeholder behavior — applied as the data-variant attribute on the list root). The fullWidthOnMobile flag is reserved for custom implementations registered through LIST_CONTAINER_STANDARD_COMPONENT_TOKEN and is ignored by ListContainerStandardComponent.
LIST_CONTAINER_STANDARD_COMPONENT_TOKEN
InjectionToken that allows replacing the default ListContainerStandardComponent with a custom implementation. Provide a Type<ListContainerBaseComponent> to override.
Extending the base class
import {
ChangeDetectionStrategy,
Component,
computed,
input,
ViewEncapsulation,
} from '@angular/core';
import {
IListContainerOptions,
LIST_CONTAINER_STANDARD_COMPONENT_TOKEN,
ListContainerBaseComponent,
ListContainerComponent,
} from '@smartsoft001/angular';
interface DocsTeamMember {
name: string;
role: string;
}
/**
* A custom list container built on `ListContainerBaseComponent`.
*
* The base contributes the `options` and `class` inputs; the implementation
* decides how the rows are framed and separated.
*/
@Component({
selector: 'docs-custom-list-container',
template: `
<ul role="list" [class]="containerClasses()">
<!--
smart-list-container renders a custom implementation through
NgComponentOutlet, which does not forward projected content. Only
options and cssClass arrive here, so a custom container owns its rows
instead of relying on ng-content.
-->
@for (member of members; track member.name) {
<li class="docs-list-container__item">
<span class="docs-list-container__name">{{ member.name }}</span>
<span class="docs-list-container__role">{{ member.role }}</span>
</li>
}
</ul>
`,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomListContainerComponent extends ListContainerBaseComponent {
// NgComponentOutlet passes 'cssClass' by canonical name, not the 'class' alias.
override cssClass = input<string>('');
members: DocsTeamMember[] = [
{ name: 'Lindsay Walton', role: 'Front-end Developer' },
{ name: 'Courtney Henry', role: 'Designer' },
{ name: 'Tom Cook', role: 'Director of Product' },
];
containerClasses = computed(() => {
const classes = ['docs-list-container'];
const variant = this.options()?.variant;
if (variant) classes.push(`docs-list-container--${variant}`);
if (this.options()?.fullWidthOnMobile) {
classes.push('docs-list-container--full-width-mobile');
}
const extra = this.cssClass();
if (extra) classes.push(extra);
return classes.join(' ');
});
}
/**
* Registering the implementation against
* `LIST_CONTAINER_STANDARD_COMPONENT_TOKEN` makes every
* `<smart-list-container>` in this injector render it instead of the standard
* variation.
*/
@Component({
selector: 'docs-list-container-custom-example',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ListContainerComponent],
providers: [
{
provide: LIST_CONTAINER_STANDARD_COMPONENT_TOKEN,
useValue: CustomListContainerComponent,
},
],
template: `<smart-list-container [options]="options" />`,
})
export class ListContainerCustomExampleComponent {
options: IListContainerOptions = {
variant: 'separate-cards',
fullWidthOnMobile: true,
};
}
Source
The component lives in packages/shared/angular/src/lib/components/list-container and is documented for Claude Code by the angular-components-list-container skill.