Configuring Gatsby to render Markdown using Semantic UI components.
2019-02-15GatsbySemantic UI
In Gatsby: Setting up a simple site we set up Gatsby to process markdown files to blog pages, including highlighting code samples.
Out of the box, using the Semantic UI styles will handle simple elements in markdown, for example headers. However we can get better styling by using Semantic UI components from our markdown.
The initial setup is covered by the docs on remark custom components. We will tweak this to render some Semantic UI components:
Install rehype-react:
yarn add rehype-react
In the page or component where you query and display posts, make a function to render the htmlAST version of your markdown using Semantic components:
const renderAst = new rehypeReact({
createElement: React.createElement,
components: {
'ul': SemanticUL,
'ol': SemanticOL,
'li': SemanticLI
},
}).Compiler
This will render list elements as custom components, which we will create next.
Create new components for lists:
const SemanticOL = ({children}) => <List relaxed ordered as='ol'>{children}</List>
const SemanticUL = ({children}) => <List relaxed bulleted as='ul'>{children}</List>
const SemanticLI = ({children}) => <List.Item as='li'>{children}</List.Item>
Both of these just pass through children to a List
with the appropriate props set. If you prefer a different style of Semantic list, just tweak the props.
htmlAst
instead of html
.Render the post with:
renderAst(post.htmlAst)
rather than:
<div dangerouslySetInnerHTML={{ __html: post.html }} />
This will get you nicely styled lists - but other Semantic components can be added in the same way. See the caveats for some gotchas!
The default styling for ul
and ol
lists in semantic doesn’t respect the relaxed
modifier. We can use list.overrides
to make line spacing match paragraphs, and to use the same relaxed padding as other Semantic lists:
ul.ui.list.relaxed li,
ol.ui.list.relaxed li,
.ui.list.relaxed > .item,
.ui.list.relaxed .list > .item {
line-height: @paragraphLineHeight;
}
ul.ui.list.relaxed li:not(:first-child),
ol.ui.list.relaxed li:not(:first-child),
.ui.list.relaxed > .item:not(:first-child),
.ui.list.relaxed .list > .item:not(:first-child) {
padding-top: @relaxedItemVerticalPadding;
}
ul.ui.list.relaxed li:not(:last-child),
ol.ui.list.relaxed li:not(:last-child),
.ui.list.relaxed > .item:not(:last-child),
.ui.list.relaxed .list > .item:not(:last-child) {
padding-bottom: @relaxedItemVerticalPadding;
}
For extra credit, we can add another component mapping:
'icon': Icon
and use it in markdown:
*Made with <icon name='heart' color='violet'></icon> by rebeam.*
Which should produce the following rather cliché result:
Made with by rebeam.
We can also display tables with Semantic:
| Bridge | Designer | Length |
|--------------|----------------|-------:|
| Brooklyn | J. A. Roebling | 1595 |
| Manhattan | G. Lindenthal | 1470 |
| Williamsburg | L. L. Buck | 1600 |
Bridge | Designer | Length |
---|---|---|
Brooklyn | J. A. Roebling | 1595 |
Manhattan | G. Lindenthal | 1470 |
Williamsburg | L. L. Buck | 1600 |
This needs the following custom components:
'table': Table,
'thead': Table.Header,
'tr': Table.Row,
'td': Table.Cell
Table
can also be customised - the example above uses celled color='violet'
, see templates/blog-post.js.
We can display blockquotes with a Semantic Message
with a quote icon:
const MessageInfo = ({children}) =>
<Message icon>
<Icon name='quote left' color='black'></Icon>
<Message.Content>
{children}
</Message.Content>
</Message>
Register this with 'blockquote': MessageInfo
in renderAst
. This will give you:
> **Nicely formatted blockquotes**
> Quote all the things.
Note we need a couple of spaces on the end of the first line to get a linebreak without a new paragraph.
You can still use other types of component directly, for example here is Alert
from react-bootstrap. Just register the component directly, e.g. 'alert': Alert
:
<alert variant="danger">**Scary message!**</alert>
2020-04-19
2020-04-18
2019-04-21
2019-03-24
2019-02-26
2019-02-20
2019-02-16
2019-02-15
2019-02-02