Card Heading

The <smart-card-heading> component provides a small composable heading region for cards, with optional slots for avatar, title, description, meta, and actions. It can be used standalone or passed as the headerTpl value to <smart-card>. It follows the Base + Standard + Wrapper pattern with an InjectionToken-based extension mechanism. The abstract CardHeadingBaseComponent defines the shared API — optional ICardHeadingOptions and cssClass (alias class). CardHeadingStandardComponent is a barebones placeholder concrete implementation. CardHeadingComponent is the public wrapper that renders CardHeadingStandardComponent by default and accepts a custom replacement via CARD_HEADING_STANDARD_COMPONENT_TOKEN.


Usage

<smart-card-heading [options]="options()" />

<ng-template #actions>
  <button type="button" (click)="onCreate()">Create new job</button>
</ng-template>

Components

CardHeadingComponent (<smart-card-heading>)

Main wrapper component. Renders CardHeadingStandardComponent by default. When CARD_HEADING_STANDARD_COMPONENT_TOKEN is provided, renders the injected component via NgComponentOutlet.

CardHeadingStandardComponent (<smart-card-heading-standard>)

Barebones placeholder concrete implementation. Renders a wrapper <div> with an optional avatar slot, a content area containing <h3> (title) + <p class="description"> (description) + optional meta slot, and an optional actions slot. Each section is rendered only when its corresponding template/string is provided. The external cssClass is applied to the wrapper. It does not include Tailwind UI styling — it exists solely as the default structural placeholder until a custom implementation is registered through the token.

CardHeadingBaseComponent (abstract)

Abstract base directive for extending custom card-heading implementations. Exposes options as an InputSignal<ICardHeadingOptions | undefined> and cssClass as an InputSignal<string> (with alias class).

API

Inputs

InputTypeDefaultDescription
optionsInputSignal<ICardHeadingOptions | undefined>-Optional configuration (title, description, slot templates)
classInputSignal<string>''External CSS classes (alias for cssClass)

ICardHeadingOptions

All properties are optional. The default CardHeadingStandardComponent consumes every property; a section is rendered only when its template/string is provided.

CARD_HEADING_STANDARD_COMPONENT_TOKEN

InjectionToken that allows replacing the default CardHeadingStandardComponent with a custom implementation. Provide a Type<CardHeadingBaseComponent> to override.

Extending the base class

import { NgTemplateOutlet } from '@angular/common';
import {
  ChangeDetectionStrategy,
  Component,
  computed,
  input,
  ViewEncapsulation,
} from '@angular/core';

import {
  CardHeadingBaseComponent,
  CardHeadingComponent,
  CARD_HEADING_STANDARD_COMPONENT_TOKEN,
  ICardHeadingOptions,
} from '@smartsoft001/angular';

/**
 * A custom card heading built on `CardHeadingBaseComponent`.
 *
 * The base contributes the `options` and `class` inputs; the implementation
 * owns the markup, including where the optional `TemplateRef` slots of
 * `ICardHeadingOptions` are projected.
 */
@Component({
  selector: 'docs-custom-card-heading',
  template: `
    <div [class]="containerClasses()">
      <div class="docs-card-heading__content">
        @if (options()?.title) {
          <h3 class="docs-card-heading__title">{{ options()!.title }}</h3>
        }
        @if (options()?.description) {
          <p class="docs-card-heading__description">
            {{ options()!.description }}
          </p>
        }
      </div>
      @if (options()?.actionsTpl) {
        <div class="docs-card-heading__actions">
          <ng-container [ngTemplateOutlet]="options()!.actionsTpl!" />
        </div>
      }
    </div>
  `,
  imports: [NgTemplateOutlet],
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomCardHeadingComponent extends CardHeadingBaseComponent {
  // 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-card-heading', this.cssClass()].filter(Boolean).join(' '),
  );
}

/**
 * Registering the implementation against `CARD_HEADING_STANDARD_COMPONENT_TOKEN`
 * makes every `<smart-card-heading>` in this injector render it instead of the
 * standard variation.
 */
@Component({
  selector: 'docs-card-heading-custom-example',
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [CardHeadingComponent],
  providers: [
    {
      provide: CARD_HEADING_STANDARD_COMPONENT_TOKEN,
      useValue: CustomCardHeadingComponent,
    },
  ],
  template: `
    <smart-card-heading
      [options]="options"
      [class]="'docs-card-heading--demo'"
    />
  `,
})
export class CardHeadingCustomExampleComponent {
  options: ICardHeadingOptions = {
    title: 'Applicant information',
    description: 'Personal details and application.',
  };
}

HyperUI preset

CardHeadingPresetComponent (<smart-card-heading-preset>) is a HyperUI-styled drop-in replacement for the standard component. It extends CardHeadingStandardComponent, is OnPush + ViewEncapsulation.None, and restyles the heading into one of four card looks selected by options.presentation.variant. All utilities are smart:-prefixed with explicit smart:dark:* variants. Content flows from the shared ICardHeadingOptions slots; the root element carries data-role="card" and per-variant zones expose data-role hooks (avatar, title, description, meta, actions, plus title-hover for the outline variant).

Because the wrapper forwards inputs canonically through NgComponentOutlet, the preset does override cssClass = input<string>('') (dropping the inherited class alias) and merges it into the root card classes.

VariantLookSlots used
authorBordered, rounded card; avatar to the side, meta <dl> (default)title, description, avatarTpl, metaTpl, actionsTpl
stackedLarge top image, title + description stacked underneathtitle, description, avatarTpl, metaTpl, actionsTpl
overlayFull-bleed image on a black backdrop, content revealed on hovertitle, description, avatarTpl, metaTpl (eyebrow), actionsTpl
outlineDashed offset border, title flips to description/action on hovertitle, description, avatarTpl, actionsTpl

presentation.variant defaults to author (also the fallback for an unknown value).

Gaps (out of scope)

HyperUI card templates 5–9 are not implemented — they need domain fields absent from ICardHeadingOptions:

  • Property card — price, address, list of numeric specs (beds/baths/area).
  • Profile with social + project links — dedicated social-icon and project-link collections (dark profile card).
  • Shaped image — a decorative clip-path/image-shape treatment with no content-driven data channel.
  • Podcast post — episode number, duration, and audio/player metadata.
  • Forum post — author, reply count, tag list, and activity timestamps.

Adding any of these would require extending ICardHeadingOptions (e.g. structured stats, links, or badges collections) before a faithful preset variant can be built.

Source

The component lives in packages/shared/angular/src/lib/components/card-heading and is documented for Claude Code by the angular-components-card-heading skill.