Tailwind Markdown Base

Tailwind Markdown Base is a simple plugin that adds base styling for elements generated by markdown or a wysiwyg from a cms.


Getting started

Installation

# Install with NPM
npm install --save @geoffcodesthings/tailwind-md-base

# Or use Yarn
yarn add @geoffcodesthings/tailwind-md-base

Usage

// tailwind.config.js
const tailwindMdBase = require('@geoffcodesthings/tailwind-md-base');

module.exports = {
  theme: {
    ...
  },
  plugins: [tailwindMdBase()],
};

Configuation

Wrapper Class

By default, Tailwind Markdown Base wraps its generated styles in a .markdown class. This, of course, is configurable in tailwind.config.js:

// tailwind.config.js
const tailwindMdBase = require('@geoffcodesthings/tailwind-md-base');

module.exports = {
  theme: {
    markdownBase: {
      wrapperClass: 'content',
    },
  },
  plugins: [tailwindMdBase()],
};

The example above would wrap the styles generated by the plugin with .content instead of the default .markdown.

Default Config

With the exception of wrapperClass, the default config is simply CSS-in-JS syntax. This allows you to customize the styles as much as you need in a standardized manner.

const defaultTheme = require('tailwindcss/resolveConfig')(
  require('tailwindcss/defaultConfig'),
).theme;

module.exports = {
  wrapperClass: 'markdown',

  h1: {
    fontSize: defaultTheme.fontSize['4xl'],
    fontWeight: defaultTheme.fontWeight.bold,
    marginTop: 0,
    marginBottom: defaultTheme.spacing[2],
  },

  h2: {
    fontSize: defaultTheme.fontSize['3xl'],
    fontWeight: defaultTheme.fontWeight.bold,
    marginTop: 0,
    marginBottom: defaultTheme.spacing[2],
  },

  h3: {
    fontSize: defaultTheme.fontSize['2xl'],
    fontWeight: defaultTheme.fontWeight.bold,
    marginTop: 0,
    marginBottom: defaultTheme.spacing[2],
  },

  h4: {
    fontSize: defaultTheme.fontSize.xl,
    fontWeight: defaultTheme.fontWeight.bold,
    marginTop: 0,
    marginBottom: defaultTheme.spacing[2],
  },

  h5: {
    fontSize: defaultTheme.fontSize.lg,
    fontWeight: defaultTheme.fontWeight.bold,
    marginTop: 0,
    marginBottom: defaultTheme.spacing[2],
  },

  h6: {
    fontSize: defaultTheme.fontSize.base,
    fontWeight: defaultTheme.fontWeight.bold,
    marginTop: 0,
    marginBottom: defaultTheme.spacing[2],
  },

  p: {
    marginTop: 0,
    marginBottom: defaultTheme.spacing[4],
  },

  a: {
    color: defaultTheme.colors.blue[500],
    textDecoration: 'none',
    '&:hover': {
      color: defaultTheme.colors.blue[600],
      textDecoration: 'none',
    },
  },

  blockquote: {
    borderColor: defaultTheme.colors.gray[300],
    borderLeftWidth: defaultTheme.borderWidth[4],
    fontWeight: defaultTheme.fontWeight.normal,
    fontStyle: 'italic',
    marginTop: defaultTheme.spacing[8],
    marginBottom: defaultTheme.spacing[8],
    paddingLeft: defaultTheme.spacing[6],
    color: defaultTheme.colors.gray[800],
    fontSize: defaultTheme.fontSize.lg,
  },

  code: {
    backgroundColor: defaultTheme.colors.gray[300],
    paddingLeft: defaultTheme.spacing[2],
    paddingRight: defaultTheme.spacing[2],
    paddingTop: defaultTheme.spacing.px,
    paddingBottom: defaultTheme.spacing.px,
    borderRadius: defaultTheme.borderRadius.default,
    fontSize: defaultTheme.fontSize.sm,
  },

  hr: {
    borderBottomWidth: defaultTheme.borderWidth.default,
    borderColor: defaultTheme.colors.gray[300],
    marginTop: defaultTheme.spacing[12],
    marginBottom: defaultTheme.spacing[12],
    borderRadius: defaultTheme.borderRadius.full,
  },

  ul: {
    listStyleType: defaultTheme.listStyleType.disc,
    listStylePosition: 'inside',
    marginTop: defaultTheme.spacing[4],
    marginBottom: defaultTheme.spacing[4],
  },

  ol: {
    listStyleType: defaultTheme.listStyleType.decimal,
    listStylePosition: 'inside',
    marginTop: defaultTheme.spacing[4],
    marginBottom: defaultTheme.spacing[4],
  },

  table: {
    width: '100%',
    color: defaultTheme.colors.gray[900],
    marginBottom: '1rem',
    padding: 0,
    borderCollapse: 'collapse',
    tr: {
      borderTopWidth: defaultTheme.borderWidth.default,
      borderColor: defaultTheme.colors.gray[700],
      backgroundColor: defaultTheme.colors.white,
      margin: 0,
      padding: 0,
      '&:nth-child(2n)': {
        backgroundColor: defaultTheme.colors.gray[100],
      },
      th: {
        fontWeight: defaultTheme.fontWeight.bold,
        borderWidth: defaultTheme.borderWidth.default,
        borderColor: defaultTheme.colors.gray[700],
        textAlign: 'left',
        margin: 0,
        padding: '6px 13px',
        '&:first-child': {
          marginTop: 0,
        },
        '&:last-child': {
          marginBottom: 0,
        },
      },
      td: {
        borderWidth: defaultTheme.borderWidth.default,
        borderColor: defaultTheme.colors.gray[700],
        textAlign: 'left',
        margin: 0,
        padding: '6px 13px',
        '&:first-child': {
          marginTop: 0,
        },
        '&:last-child': {
          marginBottom: 0,
        },
      },
    },
  },
};

Additional Styles

We currently only have default styles for the the most common elements generated by markdown. However, because of the CSS-in-JS syntax, you may add styling for any element in you config.

For example, if you want to style img elements within the .markdown namespace, you can do so like this:

// tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme');
const tailwindMdBase = require('@geoffcodesthings/tailwind-md-base');

module.exports = {
  theme: {
    markdownBase: {
      img: {
        maxWidth: '100%',
        borderWidth: defaultTheme.borderWidth.default,
        borderColor: defaultTheme.colors.gray[600],
      },
    },
  },
  plugins: [tailwindMdBase()],
};

The above example would add the following to the generated CSS:

.markdown > img {
  max-width: 100%;
  border-width: 1px;
  border-color: #718096;
}

Examples

Headings

Headings such as h1, h2, h3, h4, h5, and h6 include some basic styling inspired by frameworks like Bootstrap and Bulma.

h1. Hello World

h2. Hello World

h3. Hello World

h4. Hello World

h5. Hello World
h6. Hello World
<h1>h1. Hello World</h1>
<h2>h2. Hello World</h2>
<h3>h3. Hello World</h3>
<h4>h4. Hello World</h4>
<h5>h5. Hello World</h5>
<h6>h6. Hello World</h6>

The CSS generated for headings by this plugin is:

.markdown h1 {
  font-size: 2.25rem;
  font-weight: 700;
  margin-top: 0;
  margin-bottom: 0.5rem;
}

.markdown h2 {
  font-size: 1.875rem;
  font-weight: 700;
  margin-top: 0;
  margin-bottom: 0.5rem;
}

.markdown h3 {
  font-size: 1.5rem;
  font-weight: 700;
  margin-top: 0;
  margin-bottom: 0.5rem;
}

.markdown h4 {
  font-size: 1.25rem;
  font-weight: 700;
  margin-top: 0;
  margin-bottom: 0.5rem;
}

.markdown h5 {
  font-size: 1.125rem;
  font-weight: 700;
  margin-top: 0;
  margin-bottom: 0.5rem;
}

.markdown h6 {
  font-size: 1rem;
  font-weight: 700;
  margin-top: 0;
  margin-bottom: 0.5rem;
}

Paragraphs

Paragraphs receive 1rem of margin-bottom to provide some space between them.

Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus.

Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus.

<p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus.</p>
<p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus.</p>

The CSS generated for paragraphs by this plugin is:

.markdown p {
  margin-top: 0;
  margin-bottom: 1rem;
}

Links

Links receive some base styling such as color and text-decoration as well as :hover styling.

<a href="#">This is a link</a>

The CSS generated for links by this plugin is:

.markdown a {
  color: #4299e1;
  text-decoration: none;
}

.markdown a:hover {
  color: #3182ce,
  text-decoration: none;
}

Blockquotes

Blockquotes receive base styling inspired by GitHub's markdown styles.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.

<blockquote>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.</p>
</blockquote>

The CSS generated for blockquotes by this plugin are:

.markdown blockquote {
  border-color: #e2e8f0;
  border-left-width: 4px;
  font-weight: 400;
  font-style: italic;
  margin-top: 2rem;
  margin-bottom: 2rem;
  padding-left: 1.5rem;
  color: #2d3748;
  font-size: 1.125rem;
}

Code

The code tag is simply styled with the intention of use with inline code. I can also be used with code blocks if not using syntax highlighting.

This is what inline code looks like.

<p>This is what <code>inline code</code> looks like.</p>

The CSS generated for code tags by this plugin is:

.markdown code {
  background-color: #e2e8f0;
  padding-left: 0.5rem;
  padding-right: 0.5rem;
  padding-top: 1px;
  padding-bottom: 1px;
  border-radius: 0.25rem;
  font-size: 0.875rem;
}

Horizontal Rule

Horizontal rules receive some base styling as well. They are intentionally kept subtle.


<hr />

The CSS generated for horizontal rules by this plugin is:

.markdown hr {
  border-bottom-width: 1px;
  border-color: #e2e8f0;
  margin-top: 3rem;
  margin-bottom: 3rem;
  border-radius: 9999px;
}

Lists

Lists, ul and ol are stripped of their styling in Tailwind. This plugin adds some of those styles back.

  • Apples
  • Oranges
  • Bananas
  1. Apples
  2. Oranges
  3. Bananas
<!-- UNORDERED LIST -->
<ul>
  <li>Apples</li>
  <li>Oranges</li>
  <li>Bananas</li>
</ul>
<!-- ORDERED LIST -->
<ol>
  <li>Apples</li>
  <li>Oranges</li>
  <li>Bananas</li>
</ol>

The CSS generated for lists by this plugin is:

.markdown ul {
  list-style-type: disc;
  list-style-position: inside;
  margin-top: 1rem;
  margin-bottom: 1rem;
}

.markdown ol {
  list-style-type: decimal;
  list-style-position: inside:
  margin-top: 1rem;
  margin-bottom: 1rem;
}

Tables

Table styles are very simple with minor additions to make them look like, well... tables.

#FirstLastHandle
1MarkOtto@mdo
2JacobThornton@fat
3Larrythe Bird@twitter
<table>
  <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">First</th>
      <th scope="col">Last</th>
      <th scope="col">Handle</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">1</th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td>Larry</td>
      <td>the Bird</td>
      <td>@twitter</td>
    </tr>
  </tbody>
</table>

The CSS generated for tables by this plugin is:

.markdown table {
  width: 100%;
  color: #1a202c;
  margin-bottom: 1rem;
  padding: 0;
  border-collapse: collapse;
}

.markdown table tr {
  border-top-width: 1px;
  border-color: #4a5568;
  background-color: #fff;
  margin: 0;
  padding: 0;
}

.markdown table tr:nth-child(2n) {
  background-color: #f7fafc;
}

.markdown table tr th {
  font-weight: 700;
  border-width: 1px;
  border-color: #4a5568;
  text-align: left;
  margin: 0;
  padding: 6px 13px;
}

.markdown table tr th:first-child {
  margin-top: 0;
}

.markdown table tr th:last-child {
  margin-bottom: 0;
}

.markdown table tr td {
  border-width: 1px;
  border-color: #4a5568;
  text-align: left;
  margin: 0;
  padding: 6px 13px;
}

.markdown table tr td:first-child {
  margin-top: 0;
}

.markdown table tr td:last-child {
  margin-bottom: 0;
}

Contributing

There is plenty of room for improvement (support for more base styles, other enhancements, .etc). Contributions are welcome. If you have an idea for improvement, please submit an issue with a feature proposal first for discussion. Bug fixes can be PR'd directly. Be sure to write tests for any new features and make sure all tests pass before submitting any PR.