MediaObject
The <smart-media-object> component provides a flexible media-object layout wrapper with an InjectionToken-based extension mechanism. It pairs an image with adjacent body content (the classic media object pattern) and renders a default MediaObjectStandardComponent which can be replaced via MEDIA_OBJECT_STANDARD_COMPONENT_TOKEN.
Usage
<smart-media-object
[mediaUrl]="avatarUrl"
mediaAlt="Portrait of Lindsay Walton"
[options]="options"
>
<h4>Lindsay Walton</h4>
<p>Joined the design systems team in March.</p>
</smart-media-object>
Components
MediaObjectComponent (<smart-media-object>)
Main wrapper component. Renders MediaObjectStandardComponent by default. When MEDIA_OBJECT_STANDARD_COMPONENT_TOKEN is provided, renders the injected component via NgComponentOutlet. Projects body content into the standard via <ng-content />.
MediaObjectStandardComponent (<smart-media-object-standard>)
Default concrete implementation. Renders an <img> and a .smart-media-object-body slot inside a wrapper <div>. The wrapper exposes data-position and data-alignment attributes derived from options for CSS styling.
MediaObjectBaseComponent (abstract)
Abstract base directive for extending custom media-object implementations. Declares mediaUrl (required), mediaAlt (required), options, and cssClass.
API
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
mediaUrl | InputSignal<string> | required | Image URL |
mediaAlt | InputSignal<string> | required | Image alt text |
options | InputSignal<IMediaObjectOptions | undefined> | undefined | Layout configuration |
class | InputSignal<string> | '' | External CSS classes (alias for cssClass) |
Content Projection
The wrapper projects body content via <ng-content /> into the .smart-media-object-body slot of the standard component.
IMediaObjectOptions
The standard renders:
data-positionattribute: defaults to'left'when not provideddata-alignmentattribute: only set whenoptions.alignmentis provided
MEDIA_OBJECT_STANDARD_COMPONENT_TOKEN
InjectionToken that allows replacing the default MediaObjectStandardComponent with a custom implementation. Provide a Type<MediaObjectBaseComponent> to override.
Extending the base class
import {
ChangeDetectionStrategy,
Component,
computed,
input,
ViewEncapsulation,
} from '@angular/core';
import {
IMediaObjectOptions,
MEDIA_OBJECT_STANDARD_COMPONENT_TOKEN,
MediaObjectBaseComponent,
MediaObjectComponent,
} from '@smartsoft001/angular';
/**
* A custom media object built on `MediaObjectBaseComponent`.
*
* The base contributes the `mediaUrl`, `mediaAlt`, `options` and `class`
* inputs; the implementation owns the markup around them.
*/
@Component({
selector: 'docs-custom-media-object',
template: `
<article
[class]="containerClasses()"
[attr.data-alignment]="options()?.alignment ?? 'top'"
[attr.data-position]="options()?.position ?? 'left'"
>
<img
class="docs-media-object__media"
[src]="mediaUrl()"
[alt]="mediaAlt()"
width="64"
height="64"
/>
<!--
smart-media-object renders a custom implementation through
NgComponentOutlet, which does not forward projected content. Only
mediaUrl, mediaAlt, options and cssClass arrive here, so a custom media
object renders its own body instead of relying on ng-content.
-->
<div class="docs-media-object__body">
<h3 class="docs-media-object__title">Lindsay Walton</h3>
<p class="docs-media-object__text">
Front-end developer, joined the design systems team in March.
</p>
</div>
</article>
`,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomMediaObjectComponent extends MediaObjectBaseComponent {
// NgComponentOutlet passes 'cssClass' by canonical name, not the 'class' alias.
override cssClass = input<string>('');
containerClasses = computed(() =>
[
'docs-media-object',
this.options()?.wide ? 'docs-media-object--wide' : '',
this.options()?.nested ? 'docs-media-object--nested' : '',
this.cssClass(),
]
.filter(Boolean)
.join(' '),
);
}
/**
* Registering the implementation against
* `MEDIA_OBJECT_STANDARD_COMPONENT_TOKEN` makes every `<smart-media-object>`
* in this injector render it instead of the standard variation.
*/
@Component({
selector: 'docs-media-object-custom-example',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [MediaObjectComponent],
providers: [
{
provide: MEDIA_OBJECT_STANDARD_COMPONENT_TOKEN,
useValue: CustomMediaObjectComponent,
},
],
template: `
<smart-media-object
[mediaUrl]="mediaUrl"
mediaAlt="Portrait of Lindsay Walton"
[options]="options"
class="docs-media-object--demo"
/>
`,
})
export class MediaObjectCustomExampleComponent {
mediaUrl =
'https://images.unsplash.com/photo-1568602471122-7832951cc4c5?auto=format&fit=facearea&facepad=2&w=300&h=300&q=80';
options: IMediaObjectOptions = {
alignment: 'center',
position: 'right',
responsive: true,
};
}
Preset
MediaObjectPresetComponent (selector smart-media-object-preset) is a styled, drop-in replacement for the standard component. It extends MediaObjectStandardComponent and reuses the same inputs (mediaUrl, mediaAlt, options, class), so registering it through the token restyles every <smart-media-object>.
Look: a flex row (smart:flex smart:gap-4) with a rounded, cover-fitted thumbnail (smart:size-16 smart:rounded-lg smart:object-cover smart:shrink-0) beside small, muted body text (smart:text-sm smart:text-gray-700 smart:dark:text-gray-300). All utilities are smart:-prefixed and dark-mode aware.
IMediaObjectOptions drives every variant (no new fields):
position: 'right'reverses the row (smart:flex-row-reverse).alignment: 'top' | 'center' | 'bottom'maps tosmart:items-start | items-center | items-end;'stretched'instead makes the media fill the row height (smart:self-stretch smart:h-auto).responsive: truestacks into a column on mobile then rows out fromsm(smart:flex-col smart:sm:flex-row, reversed whenposition: 'right').nested: truetightens the gap tosmart:gap-3and indents withsmart:mt-4.wide: truewidens the thumbnail tosmart:w-32(keeping asmart:h-16height).
data-role hooks (root, media, body) and the data-position / data-alignment attributes are exposed for testing and targeting; the smart-media-object-body marker class is preserved for content projection parity with the standard component.
Register it as the standard replacement:
Class recipes live in media-object/preset/preset-classes.util.ts (getMediaObjectRootClasses, getMediaObjectMediaClasses, getMediaObjectBodyClasses).
Gaps: the media is always an <img> (no icon/video slot), and wide uses a fixed w-32/h-16 footprint rather than an intrinsic aspect ratio.
Source
The component lives in packages/shared/angular/src/lib/components/media-object and is documented for Claude Code by the angular-components-media-object skill.