Home

Awesome

npm version GitHub license

rehype-github-alerts

rehype plugin to create alerts (admonitions/callouts), mimicking the way alerts get rendered on github.com (based on this GitHub community "Alerts" discussion), currently 5 types of alerts are supported:

[!NOTE]
Highlights information that users should take into account, even when skimming.

[!TIP]
Optional information to help a user be more successful.

[!IMPORTANT]
Crucial information necessary for users to succeed.

[!WARNING]
Critical content demanding immediate user attention due to potential risks.

[!CAUTION]
Negative potential consequences of an action.

the markdown syntax for the 5 examples above is as follows:

> [!NOTE]  
> Highlights information that users should take into account, even when skimming.

> [!TIP]  
> Optional information to help a user be more successful.

> [!IMPORTANT]  
> Crucial information necessary for users to succeed.

> [!WARNING]  
> Critical content demanding immediate user attention due to potential risks.

> [!CAUTION]  
> Negative potential consequences of an action.

this is a zero configuration package as all options have defaults, but you can use them if you wish to modify default behavior, like for example by default 3 alerts are defined (with a default icon), use options.alerts to replace them with your own setup, there is also a default build that will create an output that mimics what GitHub does, but you can change the build to create whatever HTML suits your needs best, check out the "options" chapter to learn more about customization

installation

npm i rehype-github-alerts --save-exact

Demo

You can now see a live demo of this plugin on my blog, especially in my web_development chris.lu/web_development section

I also published a Next.js Next.js static MDX blog tutorial on my blog, the GitHub-like alerts using the rehype-github-alerts plugin page is about how to use rehype-github-alerts with next/js

examples

rehype example

check out the readme of the rehype example for more details about this example, all the source code is located in examples/simple-rehype-example/

how GitHub renders alerts

I created an issue on github to check how github is rendering alerts (will add more examples over time, based on feedback)

styling

add the following styles to your css to mimic GitHub's styling of alerts:

:root {
    --github-alert-default-color: rgb(208, 215, 222);
    --github-alert-note-color: rgb(9, 105, 218);
    --github-alert-tip-color: rgb(26, 127, 55);
    --github-alert-important-color: rgb(130, 80, 223);
    --github-alert-warning-color: rgb(191, 135, 0);
    --github-alert-caution-color: rgb(207, 34, 46);
}

@media (prefers-color-scheme: dark) {
    :root {
        --github-alert-default-color: rgb(48, 54, 61);
        --github-alert-note-color: rgb(31, 111, 235);
        --github-alert-tip-color: rgb(35, 134, 54);
        --github-alert-important-color: rgb(137, 87, 229);
        --github-alert-warning-color: rgb(158, 106, 3);
        --github-alert-caution-color: rgb(248, 81, 73);
    }
}

.markdown-alert {
    padding: 0.5rem 1rem;
    margin-bottom: 16px;
    border-left: 0.25em solid var(--github-alert-default-color);
}

.markdown-alert>:first-child {
    margin-top: 0;
}

.markdown-alert>:last-child {
    margin-bottom: 0;
}

.markdown-alert-note {
    border-left-color: var(--github-alert-note-color);
}

.markdown-alert-tip {
    border-left-color: var(--github-alert-tip-color);
}

.markdown-alert-important {
    border-left-color: var(--github-alert-important-color);
}

.markdown-alert-warning {
    border-left-color: var(--github-alert-warning-color);
}

.markdown-alert-caution {
    border-left-color: var(--github-alert-caution-color);
}

.markdown-alert-title {
    display: flex;
    margin-bottom: 4px;
    align-items: center;
}

.markdown-alert-title>svg {
    margin-right: 8px;
}

.markdown-alert-note .markdown-alert-title {
    color: var(--github-alert-note-color);
}

.markdown-alert-tip .markdown-alert-title {
    color: var(--github-alert-tip-color);
}

.markdown-alert-important .markdown-alert-title {
    color: var(--github-alert-important-color);
}

.markdown-alert-warning .markdown-alert-title {
    color: var(--github-alert-warning-color);
}

.markdown-alert-caution .markdown-alert-title {
    color: var(--github-alert-caution-color);
}

[!NOTE]
The above stylesheet is to get you started, it is not an exact 1 to 1 copy of what GitHub uses to style their alerts. Their stylesheet changes over time, so it is hard to keep track of the exact styling they use, but you should be able to adjust the styles yourself quickly by looking at GitHubs CSS

GitHub font family

If you also want to mimic GitHubs font choice, then you should set font-family (for the title and content of your alerts) to this:

:root {
    --frontFamily-github: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";
    --frontWeight-github: 500;
}

.markdown-alert {
    font-family: var(--frontFamily-github);
}

.markdown-alert-title {
    font-weight: var(--frontWeight-github, 500);
}

We create two new CSS variables and then use the frontFamily-github variable to set the font family of all the markdown-alert elements, and then in the title class we use frontWeight-github to make the text a bit bolder

GitHub octicons

This library uses the twbs icons, which means that the icons in the alert titles are similar but NOT exactly the same ones that twitter uses

GitHub has opensourced their Primer design system which includes icons that GitHub called octicons 😉

Here are the 5 icons you will need (they offer two versions a 16px and a 24px):

If you search for @primer/octicons on npm you will find that primer offers different packages making it easy to include the icons into your project like @primer/octicons-react, there are also community packages like the svelte-octicons, and they also have a lot of info and examples in their guides section

Rehype GitHub Alerts with octicons

First we install the octicon package:

npm i @primer/octicons --save-exact

If you use typescript, also install the types:

npm i @types/primer__octicons --save-exact --save-dev

Next we import the icons in our configuration file, we create an options object for rehype-github-alerts, we use the 5 octicons for each alert and finally use those options in the code that sets up the rehype plugins for your project:

import { rehypeGithubAlerts, IOptions as rehypeGithubAlertsOptionsType } from 'rehype-github-alerts'
import octicons from '@primer/octicons'

// this rehype-github-alerts configuration replaces
// the default icons with octicons
const rehypeGithubAlertsOptions: rehypeGithubAlertsOptionsType = {
    alerts: [
        {
            keyword: 'NOTE',
            icon: octicons.info.toSVG(),
            title: 'Note',
        },
        {
            keyword: 'TIP',
            icon: octicons['light-bulb'].toSVG(),
            title: 'Tip',
        },
        {
            keyword: 'IMPORTANT',
            icon: octicons.report.toSVG(),
            title: 'Important',
        },
        {
            keyword: 'WARNING',
            icon: octicons.alert.toSVG(),
            title: 'Warning',
        },
        {
            keyword: 'CAUTION',
            icon: octicons.stop.toSVG(),
            title: 'Caution',
        },
    ]
}

// we add rehype-github-alerts as well as the options
// to the rehype plugins configuration
rehypePlugins: [[rehypeGithubAlerts, rehypeGithubAlertsOptions]],

The output of .toSVG() will be an SVG like this:

<svg version="1.1" width="16" height="16" viewBox="0 0 16 16" class="octicon octicon-info" aria-hidden="true"></svg>

options

options (optional)

all options have default values which for most use cases should be enough, meaning there is zero configuration to do, unless you want to customize something

build option

the build option can be used to customize how alerts get rendered, this can be useful if you want to modify what css classes the elements have

the build option accepts a function that has two parameters:

alertOptions: this is an object of type IAlert, meaning it contains the options of the alert that got matched, like the keyword, icon and title originalChildren: an array of type DefaultBuildType, containing the original children (body content of the alert)

for example in your configuration file create a rehype-github-alerts build option like this:

/**
 * @typedef {import('rehype-github-alerts').IOptions} IOptions
 * @typedef {import('rehype-github-alerts').DefaultBuildType} DefaultBuildType
 */

/** @type { DefaultBuildType } */
const myGithubAlertBuild = (alertOptions, originalChildren) => {
    const alert = {
        type: 'element',
        tagName: 'div',
        properties: {
            className: [
                `markdown-alert-${alertOptions.keyword.toLowerCase()}`,
            ],
        },
        children: [
            ...originalChildren
        ],
    }

    return alert
}

/** @type { IOptions } */
const rehypeGithubAlertsOptions = {
    build: myGithubAlertBuild,
}

then use the following markdown code (important: there are two spaces after [!NOTE] to create a hard line break, see the "about soft line breaks" chapter for a more detailed explanation):

> [!NOTE]  
> I'm a note (created using a custom build)  

will yield the following HTML output:

<div class="markdown-alert-note">
    I'm a note (created using a custom build)
</div>

about "soft line breaks" support

[!IMPORTANT]
GitHub turns soft line breaks into hard line breaks by default, this plugin does NOT

option 1: If you are using rehype-github-alerts, then you need to add two spaces at the end of each line if you want to have a line break (same as you would do for markdown outside of an alert), which is the markdown syntax for a hard linebreak, like so:

> [!NOTE]  
> you MUST add 2 spaces (to all 3 lines of this example, including the first one) to create line breaks  
> if you don't want to manually add two spaces after each line, then you need to install the [remark-breaks](https://github.com/remarkjs/remark-breaks) plugin  

option 2: If you do NOT want to have to add two spaces manually after each line, then I recommend you install the plugin called remark-breaks, remark-breaks will mimic the behavior you experience on GitHub, by automatically turning a soft line break (when you hit Enter at the end of a line) into hard line breaks

As noted in the readme of the remark-breaks package README, the purpose of the remark-breaks is to:

remark-breaks turns enters into <br>s GitHub does this in a few places (comments, issues, PRs, and releases)

paragraphs separation

If you don't want a new line (1 <br> element) but also some space between two paragraphs (2 <br> elements), no matter if you have remark-breaks installed or not, then you need to add an empty line (same as you would do outside of a blockquote), like so:

> [!TIP]  
> first paragraph  
>
> second paragraph  

tests

I used the test-runner that built in node.js to add some test for common cases

All tests are located in the /test directory

To use the tests you need to create a personal GitHub access token, visit your github "New fine-grained personal access token" page to create a new token, you need to set the Gists permission under Account permissions to read/write, then click on "Generate token" to create your new token. If you new to GitHub tokens, then you may want to check out the GitHub documentation "Creating a fine-grained personal access token", this token will be used by one of the dependencies of the test suite to create gists based on input markdown and generate HTML files containing the output GitHub has produced, for more about this package check out it's the "create-gfm-fixtures" GitHub repository

When you have your token, make a copy of the .env.example and rename it to .env, then insert your token and save it

To run the tests use the following command:

npm run test

[!NOTE]
this will build the plugin and then run the test coverage command

types

If you use typescript and intend to edit the options, for example to create custom alerts, then you may want to use the types provided by this library:

import { rehypeGithubAlerts, IOptions } from 'rehype-github-alerts'

const myOptions: IOptions = {
    alerts: [
        {
            keyword: 'MY_ALERT',
            icon: '<svg width="16" height="16" viewBox="0 0 16 16"/></svg>',
            title: 'My Alert',
        },
    ],
}

If your configuration file is written in javascript, then you can use the types likes this:

on top of your file add this jsdoc typedef at the beginning of the file:

/**
 * @typedef {import('rehype-github-alerts').IOptions} IOptions
 */

and then in your code use the rehype-github-alerts type by placing a jsdoc @type tag over the options, like so:

/** @type { IOptions } */
const rehypeGithubAlertsOptions = {
    supportLegacy: false,
}
<details> <summary>here is a full example of a next.js next.config.mjs configuration file</summary>
/**
 * @typedef {import('rehype-github-alerts').IOptions} IOptions
 */

import WithMDX from '@next/mdx'
import remarkBreaks from 'remark-breaks'
import remarkGfm from 'remark-gfm'
import { rehypeGithubAlerts }  from 'rehype-github-alerts'

const nextConfig = (/*phase*/) => {

    // https://github.com/remarkjs/remark-gfm
    // If you use remark-gfm, you'll need to use next.config.mjs
    // as the package is ESM only
    const remarkGfmOptions = {
        singleTilde: false,
    }

    // https://github.com/chrisweb/rehype-github-alerts
    /** @type { IOptions } */
    const rehypeGithubAlertsOptions = {
        supportLegacy: false,
    }

    const withMDX = WithMDX({
        extension: /\.mdx?$/,
        options: {
            remarkPlugins: [remarkBreaks, [remarkGfm, remarkGfmOptions]],
            rehypePlugins: [[rehypeGithubAlerts, rehypeGithubAlertsOptions]],
        },
    })

    /** @type {import('next').NextConfig} */
    const nextConfig = {
        experimental: {
            // experimental use rust compiler for MDX
            // as of now (07.10.2023) there is no support for rehype plugins
            // this is why it is currently disabled
            mdxRs: false,
        },
        // configure pageExtensions to include md and mdx
        pageExtensions: ['ts', 'tsx', 'js', 'jsx', 'md', 'mdx'],
    }

    return withMDX(nextConfig)

}

export default nextConfig

The Next.js configuration example above assumes that you have installed the packages @next/mdx, @mdx-js/loader, remark-breaks, remark-gfm and rehype-github-alerts

</details>

legacy syntax

as of 14 November 2023 GitHub has removed support for legacy syntax, the legacy syntax is supported by this plugin but as of now turned off by default

legacy markdown (mdx) syntax:

> **!Note**  
> I'm a note :wave:  

> **!Important**  
> I'm important  

> **!Warning**  
> I'm a warning  

you can turn ON legacy support via the options like so:

const myRehypeGithubAlertsOptions = {
    supportLegacy: true,
}

TODOs

bugs

if you find a bug, please open an issue in the rehype-github-alerts issues page on github, try to describe the bug you encountered as best as you can and if possible add some examples of the markdown / mdx content or code that you used when you found the bug, I or a contributor will try to look into it asap

feedback

If you have an idea to improve this project please use the "NEW Feature Request" issue template or if you have any feedback about this package you may want to post it in the rehype discussion about this plugin

contributing

PRs are welcome 😉

To get started, please check out the CONTRIBUTING.md guide of this project

alternatives

an alternative to this package if you want to have github like alerts but do it with a remark plugin instead of a rehype plugin is remark-github-beta-blockquote-admonitions

optional packages

if you use this package, there are other packages you might want to install too, for example:

icons

the 5 icons used in this package are from "Bootstrap Icons" repository and licensed under MIT

note to self

Have downgraded eslint for now, ESLint issue #19134 explains the problem and there is a PR #10339 getting merged anytime soon