npm package: @mzebley/mark-down-angular
Description: mark↓ Angular Adapter
Latest version: 1.2.4

# mark↓ Angular Adapter

_(published as `@mzebley/mark-down-angular`)_

Angular bindings for the [mark↓ core runtime](../core/README.md). This package wraps `SnippetClient` with Angular-friendly providers, services, and components so you can render Markdown snippets safely inside your application. For background on the monorepo, see the [root README](../../README.md).

## Table of contents

1. [Installation](#installation)
2. [Bootstrap configuration](#bootstrap-configuration)
3. [Consuming snippets](#consuming-snippets)
4. [`<snippet-view>` component](#snippet-view-component)
5. [Server-side rendering](#server-side-rendering)
6. [Testing tips](#testing-tips)
7. [Roadmap](#roadmap)
8. [Related packages](#related-packages)

## Installation

Install the Angular adapter alongside the core runtime:

```bash
npm install @mzebley/mark-down-angular @mzebley/mark-down
```

You will also need a manifest generated by the [CLI](../cli/README.md).

## Bootstrap configuration

Provide a shared `SnippetClient` from your root bootstrap call or feature module:

```ts
import { bootstrapApplication } from "@angular/platform-browser";
import { provideSnippetClient } from "@mzebley/mark-down/angular";

bootstrapApplication(AppComponent, {
  providers: [
    ...provideSnippetClient({
      manifest: "/assets/content/snippets/manifest.json",
      base: "/assets/content/snippets",
    }),
  ],
});
```

`provideSnippetClient` wires up the client as an Angular provider using the same options supported by the core runtime (`manifest`, `base`, `fetch`, `frontMatter`, `cache`, `verbose`). Prefer the scoped `@mzebley/mark-down/angular` entry point for tree-shaking and clearer typing. For backwards compatibility this package also re-exports `provideMarkDown`, `MARK_DOWN_CLIENT`, and the legacy `SnippetService` name.

### Angular compatibility

| Angular version | Status       |
| --------------- | ------------ |
| 17.x            | ✅ Supported |
| 18.x            | ✅ Supported |
| 19.x            | ✅ Supported |
| 20.x            | ✅ Supported |

The package declares peer dependency ranges `>=17 <21` so projects running any currently supported Angular major release can install without `--legacy-peer-deps`.

## Consuming snippets

Inject `MarkdownSnippetService` into components or services to access Observables for snippets:

```ts
import { Component, inject } from "@angular/core";
import { MarkdownSnippetService } from "@mzebley/mark-down/angular";

@Component({
  selector: "docs-hero",
  template: `
    <ng-container *ngIf="hero$ | async as hero">
      <h1>{{ hero.title }}</h1>
      <div [innerHTML]="hero.html"></div>
    </ng-container>
  `,
})
export class DocsHeroComponent {
  private readonly snippets = inject(MarkdownSnippetService);
  readonly hero$ = this.snippets.get("getting-started-welcome");
}
```

The service mirrors the core client APIs (`get`, `listAll`, `listByType`, `listByGroup`, `search`) but returns cold Observables that share cached results across subscribers.

## `<snippet-view>` component

Render snippets declaratively with the bundled standalone component:

```html
<snippet-view
  [slug]="'components-button'"
  (loaded)="onSnippetLoaded($event)"
></snippet-view>
```

Features:

- Uses Angular's `DomSanitizer` for trusted HTML binding and DOMPurify in browser rendering.
- Emits a `loaded` event once the snippet resolves so parent components can react.
- Provides a loading placeholder and gracefully emits `undefined` when the slug cannot be resolved.
- Supports `class`/`ngClass` bindings for styling since it renders a standard `<div>`.

### Security warning

The Angular adapter is intentionally compatible with untrusted/unsanitized snippet pipelines. That flexibility is a feature, but it means you must decide where sanitization happens:

- For untrusted content, sanitize in `SnippetClient` (`sanitize` option) and/or during build with `mark-down compile-page --sanitize`.
- If sanitization is disabled, snippet HTML is treated as trusted and may include dangerous markup.

## Server-side rendering

When running in Angular Universal, supply a server-compatible fetch implementation:

```ts
import fetch from "node-fetch";

provideSnippetClient({
  manifest: () => import("../snippets-index.json"),
  fetch: (url) =>
    fetch(url).then((response) => {
      if (!response.ok) {
        throw new Error(`Request failed with status ${response.status}`);
      }
      return response;
    }),
});
```

The provider forwards all options to the underlying `SnippetClient`, so SSR, custom cache policies, and preloaded manifests work exactly like the core package.

## Testing tips

- Provide a mock manifest array during tests: `provideSnippetClient({ manifest: mockManifest })`.
- Use `MarkdownSnippetService` with the Angular `TestBed` to assert filtering behaviour.
- Pair with the [example application](../../examples/basic/README.md) to see how snippets integrate with routing and feature modules.

## Roadmap

- **Template primitives** – structural directives for rendering snippet lists via `*markDownSnippets`.
- **AsyncPipe optimisations** – helpers that automatically unsubscribe / reuse cached Observables when using standalone components.
- **Schematics** – Angular CLI generator for wiring `provideMarkDown` + `SnippetViewComponent`.
- **SSR hydration helpers** – share manifest snapshots between server and browser to avoid double fetching.

## Related packages

- [Core runtime](../core/README.md)
- [CLI](../cli/README.md)
- [React adapter](../react/README.md)
- [Project overview](../../README.md)