|
| 1 | +--- |
| 2 | +title: Text Style |
| 3 | +--- |
| 4 | + |
| 5 | +# Text Style ((tag|VitePress plugin|blue)) ((tag|markdown-it|orange)) |
| 6 | + |
| 7 | +[[readingTime]] |
| 8 | + |
| 9 | +[](https://github.com/binarynoir/vitepress-text-style) [](https://www.npmjs.com/package/@binarynoir/vitepress-text-style) [](https://github.com/binarynoir/vitepress-text-style/actions/workflows/ci.yml) [](https://github.com/binarynoir/vitepress-text-style/blob/main/LICENSE) |
| 10 | + |
| 11 | +`@binarynoir/vitepress-text-style` colors and sizes text inline, without writing HTML. Write `[t:red]warning[/t]` or `[t::1.2em]larger[/t]` and get a styled `<span>`. Values are checked before they reach the page, code is left alone, and the text inside is still Markdown. |
| 12 | + |
| 13 | +It uses the same `[t:color:size]` syntax as the text-style plugin many VuePress sites carry, so pages can move to VitePress without being rewritten. Every example below is live: each one shows the Markdown as written, then the same Markdown rendered by this site. |
| 14 | + |
| 15 | +## See it live |
| 16 | + |
| 17 | +```md |
| 18 | +A [t:red]red[/t] word, a [t:blue:1.4em]big blue[/t] one, and a [t::small]small[/t] one. |
| 19 | +``` |
| 20 | + |
| 21 | +::: info On the page |
| 22 | +A [t:red]red[/t] word, a [t:blue:1.4em]big blue[/t] one, and a [t::small]small[/t] one. |
| 23 | +::: |
| 24 | + |
| 25 | +## Install |
| 26 | + |
| 27 | +```sh |
| 28 | +npm install --save-dev @binarynoir/vitepress-text-style |
| 29 | +``` |
| 30 | + |
| 31 | +## Use |
| 32 | + |
| 33 | +Register it in VitePress's `markdown.config` hook, the same place as any other markdown-it plugin: |
| 34 | + |
| 35 | +```ts |
| 36 | +// .vitepress/config.mts |
| 37 | +import { defineConfig } from 'vitepress'; |
| 38 | +import { markdownTextStyle } from '@binarynoir/vitepress-text-style'; |
| 39 | + |
| 40 | +export default defineConfig({ |
| 41 | + markdown: { |
| 42 | + config(md) { |
| 43 | + md.use(markdownTextStyle); |
| 44 | + }, |
| 45 | + }, |
| 46 | +}); |
| 47 | +``` |
| 48 | + |
| 49 | +Or wrap the config with `withTextStyle` from `@binarynoir/vitepress-text-style/vitepress`. It keeps any `markdown.config` you already have, including one set by another `withX()` wrapper. |
| 50 | + |
| 51 | +```ts |
| 52 | +import { withTextStyle } from '@binarynoir/vitepress-text-style/vitepress'; |
| 53 | + |
| 54 | +export default withTextStyle( |
| 55 | + defineConfig({ |
| 56 | + // ...your config |
| 57 | + }), |
| 58 | +); |
| 59 | +``` |
| 60 | + |
| 61 | +## Syntax |
| 62 | + |
| 63 | +```md |
| 64 | +[t:color]text[/t] |
| 65 | +[t:color:size]text[/t] |
| 66 | +[t::size]text[/t] |
| 67 | +``` |
| 68 | + |
| 69 | +Either value can be left out, but not both. Whitespace around the values and the text is ignored, so `[t: red ] text [/t]` is the same as `[t:red]text[/t]`. |
| 70 | + |
| 71 | +### Markdown inside |
| 72 | + |
| 73 | +The text in a span is parsed as Markdown, so emphasis, code, links and badges all work inside it: |
| 74 | + |
| 75 | +```md |
| 76 | +[t:green]**Done:** see [the overview](/plugins/) and run `npm test`. ((tag|Shipped|green))[/t] |
| 77 | +``` |
| 78 | + |
| 79 | +::: info On the page |
| 80 | +[t:green]**Done:** see [the overview](/plugins/) and run `npm test`. ((tag|Shipped|green))[/t] |
| 81 | +::: |
| 82 | + |
| 83 | +### Nesting |
| 84 | + |
| 85 | +Spans nest, and each `[/t]` closes its own opener: |
| 86 | + |
| 87 | +```md |
| 88 | +[t:var(--vp-c-brand-1)]The brand color, with [t::1.5em]a larger word[/t] in the middle.[/t] |
| 89 | +``` |
| 90 | + |
| 91 | +::: info On the page |
| 92 | +[t:var(--vp-c-brand-1)]The brand color, with [t::1.5em]a larger word[/t] in the middle.[/t] |
| 93 | +::: |
| 94 | + |
| 95 | +### Headings, lists and tables |
| 96 | + |
| 97 | +A span stays within one paragraph, heading, list item or table cell. |
| 98 | + |
| 99 | +```md |
| 100 | +- [t:var(--vp-c-tip-1)]Ready[/t] for review |
| 101 | +- [t:var(--vp-c-danger-1)]Blocked[/t] on a dependency |
| 102 | + |
| 103 | +| Status | Count | |
| 104 | +| ------------------------------------ | ----- | |
| 105 | +| [t:var(--vp-c-warning-1)]Pending[/t] | 3 | |
| 106 | +``` |
| 107 | + |
| 108 | +::: info On the page |
| 109 | + |
| 110 | +- [t:var(--vp-c-tip-1)]Ready[/t] for review |
| 111 | +- [t:var(--vp-c-danger-1)]Blocked[/t] on a dependency |
| 112 | + |
| 113 | +| Status | Count | |
| 114 | +| ------------------------------------ | ----- | |
| 115 | +| [t:var(--vp-c-warning-1)]Pending[/t] | 3 | |
| 116 | + |
| 117 | +::: |
| 118 | + |
| 119 | +### Code is left alone |
| 120 | + |
| 121 | +Inline code, fenced code and indented code blocks are never styled, so you can show the syntax itself in backticks, as this page does. To show it as text outside code, escape the opener with a backslash: |
| 122 | + |
| 123 | +```md |
| 124 | +In code: `[t:red]not styled[/t]`. Escaped: \[t:red]not styled[/t]. |
| 125 | +``` |
| 126 | + |
| 127 | +::: info On the page |
| 128 | +In code: `[t:red]not styled[/t]`. Escaped: \[t:red]not styled[/t]. |
| 129 | +::: |
| 130 | + |
| 131 | +## Values |
| 132 | + |
| 133 | +### Colors |
| 134 | + |
| 135 | +| Form | Examples | |
| 136 | +| --------------- | ------------------------------------------------------------------------------- | |
| 137 | +| Named colors | `red`, `rebeccapurple`, `currentColor`, `transparent` | |
| 138 | +| Hex | `#f00`, `#f008`, `#ff0000`, `#ff000080` | |
| 139 | +| Color functions | `rgb(255 0 0)`, `rgba(255,0,0,.5)`, `hsl(120deg 50% 50%)`, `oklch(70% 0.1 200)` | |
| 140 | +| CSS variables | `var(--vp-c-brand-1)` | |
| 141 | + |
| 142 | +### Sizes |
| 143 | + |
| 144 | +| Form | Examples | |
| 145 | +| --------------- | ----------------------------------------------- | |
| 146 | +| Number and unit | `16px`, `24pt`, `1.2em`, `.8rem`, `150%`, `5vw` | |
| 147 | +| Keywords | `xx-small` to `xxx-large`, `smaller`, `larger` | |
| 148 | +| CSS variables | `var(--my-size)` | |
| 149 | + |
| 150 | +```md |
| 151 | +[t:#e67e22]Hex[/t], [t:rgb(46 134 222)]rgb()[/t], [t:hsl(280deg 60% 55%)]hsl()[/t], [t:oklch(65% 0.2 145)]oklch()[/t], and [t::x-large]x-large[/t]. |
| 152 | +``` |
| 153 | + |
| 154 | +::: info On the page |
| 155 | +[t:#e67e22]Hex[/t], [t:rgb(46 134 222)]rgb()[/t], [t:hsl(280deg 60% 55%)]hsl()[/t], [t:oklch(65% 0.2 145)]oklch()[/t], and [t::x-large]x-large[/t]. |
| 156 | +::: |
| 157 | + |
| 158 | +### Light and dark mode |
| 159 | + |
| 160 | +A fixed color such as `darkblue` can be hard to read on a dark background. VitePress's theme variables change with the mode, so text colored with them stays readable in both. Switch this site's appearance and compare: |
| 161 | + |
| 162 | +```md |
| 163 | +[t:darkblue]darkblue[/t] against [t:var(--vp-c-brand-1)]var(--vp-c-brand-1)[/t] and [t:var(--vp-c-danger-1)]var(--vp-c-danger-1)[/t]. |
| 164 | +``` |
| 165 | + |
| 166 | +::: info On the page |
| 167 | +[t:darkblue]darkblue[/t] against [t:var(--vp-c-brand-1)]var(--vp-c-brand-1)[/t] and [t:var(--vp-c-danger-1)]var(--vp-c-danger-1)[/t]. |
| 168 | +::: |
| 169 | + |
| 170 | +### Invalid values |
| 171 | + |
| 172 | +Anything the plugin doesn't recognise is dropped. If one value is invalid the other is still applied. If neither is, the whole span is shown as written, so a typo is visible on the page instead of silently doing nothing: |
| 173 | + |
| 174 | +```md |
| 175 | +[t:red:huge]Red at the normal size[/t]. [t:#ff00000]A seven-digit hex, shown as written[/t]. |
| 176 | +``` |
| 177 | + |
| 178 | +::: info On the page |
| 179 | +[t:red:huge]Red at the normal size[/t]. [t:#ff00000]A seven-digit hex, shown as written[/t]. |
| 180 | +::: |
| 181 | + |
| 182 | +Named colors are accepted as any single word, so a misspelled name such as `redd` still becomes a span, and the browser ignores the color. No value can contain `;`, quotes or `<`, so a marker can't add other CSS or break out of the `style` attribute. |
| 183 | + |
| 184 | +## Options |
| 185 | + |
| 186 | +`markdownTextStyle(md, options)` and `withTextStyle(config, options)` take: |
| 187 | + |
| 188 | +| Option | Default | Description | |
| 189 | +| ----------- | ------- | --------------------------------------------------------------------------------------- | |
| 190 | +| `className` | none | A class added to every styled `<span>`, for theme CSS that should apply to all of them. | |
| 191 | + |
| 192 | +## Per-page settings |
| 193 | + |
| 194 | +A page turns the plugin off with `textStyle: false` in its frontmatter. On that page `[t:…]` is shown as written. |
| 195 | + |
| 196 | +```md |
| 197 | +--- |
| 198 | +textStyle: false |
| 199 | +--- |
| 200 | +``` |
| 201 | + |
| 202 | +## Migrating from VuePress |
| 203 | + |
| 204 | +The syntax and output match the VuePress text-style plugin, with a few differences: |
| 205 | + |
| 206 | +- **Code is detected by markdown-it, not by splitting on backticks.** Indented code blocks and multi-backtick code spans are now left alone too. |
| 207 | +- **The text is Markdown.** `**bold**` inside a span is bold, and text containing `[`, such as `array[0]`, now works. |
| 208 | +- **Spans nest.** |
| 209 | +- **More values are accepted:** 4- and 8-digit hex, modern color functions, CSS variables, and `vmin`, `vmax` and `q` sizes. |
| 210 | + |
| 211 | +[README Index](/plugins/readme-index/) helps with the other half of a VuePress move: it serves `README.md` as a folder's index page. |
| 212 | + |
| 213 | +## Limits |
| 214 | + |
| 215 | +- **A span can't go inside a link's text.** `[[t:red]docs[/t]](/docs)` isn't a link, because markdown-it doesn't allow brackets another rule consumed inside a link label. Put the span around the link instead: `[t:red][docs](/docs)[/t]`. |
| 216 | +- **Inline styles only.** For styling you reuse, a class in your theme CSS is easier to change later; `className` adds one to every span. |
| 217 | + |
| 218 | +[Source and full README on GitHub](https://github.com/binarynoir/vitepress-text-style) |
0 commit comments