Components
Angular components inside Markdown: registration, children, and how a tag is told apart from HTML.
A tag in your Markdown can become a real Angular component. This is the centre of Blasdoc, so it is worth being precise about how a tag is recognised, how it is resolved, and what happens when it is not.
Using one
<app-button variant="primary">Comprar</app-button>Registering
A component is only ever instantiated when you have registered it. Nothing in the content can reach anything else.
On a page, listed where it is used:
@Component({
selector: 'app-guide-page',
templateMD,
components: [AppButton, AppCallout],
})
export class GuidePage {}Application-wide, when many documents share a component:
provideBlasdoc({
components: {
'app-button': AppButton,
'app-callout': AppCallout,
},
});The list form reads each component's own selector, so the name cannot drift from the class. The record form is there when you want a different name, or a lazy loader.
Children
Children are projected through <ng-content />, and they are Markdown:
<app-callout type="warning">
This is **Markdown** inside a component, with a [link](/docs).
</app-callout>Nesting works to any depth, and a component may span several Markdown blocks.
Self-closing
<app-spacer />HTML is not a component
<div> stays a div. The rule is the tag name: a name containing a dash is a
component, everything else is HTML.
<div>A plain div, rendered as HTML.</div>You can change the rule:
provideBlasdoc({
parseOptions: {
isComponentName: (name) => name.startsWith('app-'),
},
});Unknown components
The parser does not know your registry — it records a component node either way. The runtime is what reports the problem:
BLASDOC_UNKNOWN_COMPONENT Unknown component "app-missing".Nothing is instantiated on a guess. See Diagnostics.
The Markdown boundary
CommonMark only recognises HTML-shaped tags, so <app-callout type="warning">
arrives as a raw HTML block while <app-button [disabled]="x"> arrives as plain
text — [disabled] is not a valid HTML attribute name. Blasdoc re-reads both
through its own tokenizer, so the two spellings produce the same IR.
Two consequences worth knowing:
A paragraph is transparent to tags: it is only materialised once no tag
crossed its boundary, so a component can span several blocks, and a paragraph
holding nothing but tags is dropped rather than wrapping your component in a
stray <p>.