Blocks
You can decorate markdown elements with a special syntax, Code Hike will transform them into objects and pass them as props to your components.
This lets you add structure to your markdown content that you can then use to render it in any way you want using React components.
import { MyComponent } from "./my-component"<MyComponent>The two towers## !mordor Barad-dûrThe Dark TowerSauron's fortress## !isengard OrthancSaruman's stronghold</MyComponent>
export function MyComponent(props) {props = {children: <p>The two towers</p>,mordor: {title: "Barad-dûr",children: (<><p>The Dark Tower</p><p>Sauron's fortress</p></>),},isengard: {title: "Orthanc",children: <p>Saruman's stronghold</p>,},}...}
The !mordor decoration at the start of the first heading tells Code Hike to group the content between this heading and the next one, the !isengard heading. That content group becomes a block object, that you can then use in your components.
Images, CodeBlocks, and Paragraphs
Besides headings, you can add the !
decoration to images, codeblocks, and paragraphs.
import { MyComponent } from "./my-component"<MyComponent>The Fellowship of the Ring!author Tolkien![!cover Gandalf](/gandalf.jpg "a wizard")```js !riddle mellon.jsspeak("friend")```## !moria western gateSpeak, friend, and enter</MyComponent>
export function MyComponent(props) {props = {children: <p>The Fellowship of the Ring</p>,author: "Tolkien",cover: {alt: "Gandalf",url: "/gandalf.jpg",title: "a wizard",},riddle: {lang: "js",meta: "mellon.js",value: 'speak("friend")',},moria: {title: "western gate",children: <p>Speak, friend, and enter</p>,},}...}
Lists
You can use !!
, instead of !
, to list all the blocks with the same decoration in an array.
import { MyComponent } from "./my-component"<MyComponent>The Brandybuck Brunch## !!breakfasts firstGrilled mushrooms## !!breakfasts secondApple pancakes</MyComponent>
export function MyComponent(props) {props = {children: <p>The Brandybuck Brunch</p>,breakfasts: [{title: "first",children: <p>Grilled mushrooms</p>,},{title: "second",children: <p>Apple pancakes</p>,},],}...}
The same applies to images, codeblocks, and paragraphs.
Nesting
You can use headings with different levels to create nested blocks.
import { MyComponent } from "./my-component"<MyComponent>The Rings of Power## !masterThe One Ring### !!rings ElvesThree rings### !!rings DwarvesSeven rings### !!rings MenNine rings</MyComponent>
export function MyComponent(props) {props = {children: <p>The Rings of Power</p>,master: {title: "",children: <p>The One Ring</p>,rings: [{title: "Elves",children: <p>Three rings</p>,},{title: "Dwarves",children: <p>Seven rings</p>,},{title: "Men",children: <p>Nine rings</p>,},],},}...}
Schema
You can use zod schemas to validate the content coming from the MDX.
npm install zod
This has two benefits:
- Type-safe markdown: You'll see an error if the content doesn't match the schema
- Better tooling:You'll get autocompletion and type checking in your editor
import { MyComponent } from "./my-component"<MyComponent>The Fellowship of the Ring!author Tolkien![!cover Gandalf](/gandalf.jpg "a wizard")```js !riddle mellon.jsspeak("friend")```## !!breakfasts firstGrilled mushrooms## !!breakfasts secondApple pancakes</MyComponent>
import { z } from "zod"import {parseProps, Block, CodeBlock, ImageBlock} from "codehike/blocks"const Schema = Block.extend({author: z.string(),cover: ImageBlock.optional(),riddle: CodeBlock,breakfasts: z.array(Block),})export function MyComponent(props) {const data = parseProps(props, Schema)const data: {title: stringchildren?: ReactNodeauthor: stringcover?: {alt: stringurl: stringtitle: string}riddle: {lang: stringmeta: stringvalue: string}breakfasts: {title: stringchildren?: ReactNode}[]}...}
Root level blocks
You can use decorated elements directly in the root of your Markdown/MDX file.
The Brandybuck Brunch## !!breakfasts firstGrilled mushrooms## !!breakfasts secondApple pancakes
import { parseRoot } from "codehike/blocks"import MDX from "./content.md"const Schema = Block.extend({breakfasts: z.array(Block),})export default function Page() {const data = parseRoot(MDX, Schema)...}
Component blocks
Coming soon
Examples
The code tooltip example shows how to use blocks at a component level.
The scrollycoding example shows how to use blocks for layout at a page level.