Comark syntax
Comark (formerly MDC, “Markdown components”) is a way to use components and attributes without writing JSX. It is off by default. Turn it on in the headmatter:
---title: My talkcomark: true---mdc: true is accepted as the older name. The Vite plugin, kadal-deck check, the VS Code
extension and the hosted builder all read it. Everything MDX already does keeps working beside it.
Inline components
Section titled “Inline components”:name[content]{attributes} is a component inside a line. The name is a component’s name in
kebab-case or as written (badge and Badge are both <Badge>), and the brackets hold its
children:
The release is :badge[New]{tone="good"} and ships :icon{name="rocket"} today.That is <Badge tone="good">New</Badge> and <Icon name="rocket" />. Any built-in component works,
and so do your own from src/components.tsx (:price-tag is <PriceTag>). A name that is an HTML
element (:span, ::section) renders as that element.
Attributes on anything
Section titled “Attributes on anything”{…} straight after a span of text, bold, code, a link or an image puts attributes on it:
This is [red text]{style="color: crimson"} and this is [the key number]{.big-number #headline}.
**Bold**{.accent} and `code`{style="font-size: 2em"} take them too.
[The docs](https://deck.kadal.cc/docs/){target=_blank} open in a new tab.
{width=240 lazy}In {…} |
Means |
|---|---|
.name |
a class (several: .a .b or .a.b), from src/styles.css or Tailwind |
#name |
an id |
key="value", key=value |
an attribute or prop, as a string |
key alone |
true (lazy on an image becomes loading="lazy") |
style="color: red; font-size: 2em" |
a style, turned into an object for a component |
:key="…" |
data: JSON or a JavaScript-style literal (:n="3", :tags='["a", "b"]'), read and never run |
A {…} that follows nothing it can apply to stays as text, and kadal-deck check warns about it.
Event handlers (onclick="…") can’t be strings in a deck and are dropped with a warning.
Blocks
Section titled “Blocks”A line ::name{attributes} opens a block component and a line :: closes it. What is between is
Markdown, the component’s children:
::callout{kind="warn"}The **default** slot is the body.#titleA *named* slot becomes the `title` prop.::A line #name inside the block starts a named slot: everything after it, up to the next slot
or the end, becomes the prop of that name (#my-footer becomes myFooter). A slot of one paragraph
arrives as its text; a longer one keeps its blocks. #default returns to the body.
Bound values pass data rather than strings:
::callout{kind="tip" title="Bound props"}A tag with `:name="…"` passes data: :badge[3 tags]{:tone="'accent'"}::Nesting
Section titled “Nesting”A block inside a block takes one colon more than the block it is in:
::cols{:n="2"}:::glass{tone="accent"}Left card, inside `<Cols>`.::::::glassRight card.:::::An HTML element name makes a plain element that can hold any Markdown, lists and code included:
::section{.two-up}- an HTML element block- holds any Markdown::A block left open closes at the end of what it is in, with a warning.
What keeps its meaning
Section titled “What keeps its meaning”With Comark on, the deck’s own colon syntax is read first and behaves as before:
::right::,::left::and the other slot markers still split a layout;::code-group…::is still a code group;{expression}that is not an attribute list is still an MDX expression ({1 + 1}prints 2);- code spans and fences are never read as Comark;
- colons in prose, times (
10:30), URLs and emoji shortcodes (:smile:) stay text.
Checking it
Section titled “Checking it”kadal-deck check reads Comark components like JSX ones: an unknown name is an error with the nearest
match, and a Comark mistake (an unclosed block, attributes that follow nothing) is a warning on its
line. Without comark: true, a slide written in Comark is an MDX error, and the message says how to
turn Comark on.