Getting Started with Nextfolio
Start with the essentials
Nextfolio gives you a focused writing setup:
- content-driven posts with frontmatter validation
- readable typography with Tailwind Typography
- theme variables for light and dark mode
Write your first post
Create a new file in src/content/blog, add frontmatter, and write Markdown or MDX.
---title: My First Postdesc: Notes from my first week.pubDate: 2026-04-30tags: [notes]---Code Blocks
Basic Code Block
<!doctype html><html lang="en"> <head> <meta charset="utf-8" /> <title>Example HTML5 Document</title> </head> <body> <p>Test</p> </body></html>Filename Tabs
Add a title to show a filename tab above the code block:
const siteConfig = { name: 'My Blog', url: 'https://example.com', lang: 'en',}export default siteConfig:root { --accent: #2337ff; --gray: 96, 115, 159;}
body { font-family: system-ui, sans-serif; color: rgb(var(--gray));}Line Numbers
Enable line numbers per block with showLineNumbers:
export function fibonacci(n: number): number { if (n <= 1) return n return fibonacci(n - 1) + fibonacci(n - 2)}
export function factorial(n: number): number { if (n <= 1) return 1 return n * factorial(n - 1)}
console.log(fibonacci(10)) // 55console.log(factorial(5)) // 120You can also set a custom starting number:
def greet(name: str) -> str: return f"Hello, {name}!"
for i in range(3): print(greet(f"User {i}"))Highlighted Lines
Highlight specific lines with {lineNumbers}:
const items = ['apple', 'banana', 'cherry']const filtered = items.filter(item => item.length > 5) // highlightedconsole.log(filtered) // ['banana', 'cherry']const sorted = filtered.sort()console.log(sorted)Insertions and Deletions (Diffs)
Show additions and removals with ins and del:
function getGreeting(name) { return 'Hello, ' + name + '!' const greeting = `Hello, ${name}!` return greeting}You can also use the mark marker for neutral highlights:
export function loadData() { const data = fetch('/api/data') // This function is critical to the app return data.json()}Word Wrap
Long lines wrap by default. Disable per block with wrap=false:
echo "This is a very long command that demonstrates how word wrapping works in Expressive Code blocks when the content exceeds the available width"Collapsible Sections
Collapse repetitive or less important code with collapse:
import { createApp } from 'vue'import App from './App.vue'
// ---vvv--- Collapsed boilerplate ---vvv---11 collapsed lines
const app = createApp(App)app.use(router)app.use(store)app.use(i18n)app.directive('focus', {})app.component('GlobalComponent', {})app.mixin({})app.config.errorHandler = () => {}app.config.warnHandler = () => {}// ---^^^--- End collapsed section ---^^^---
// Your actual app logic starts hereapp.mount('#app')Terminal Blocks
Shell commands automatically get a terminal-style frame:
npm create astro@latest -- --template blogcd my-blognpm installnpm run devCombined Features
You can combine multiple features in a single block:
import type { ReactNode } from 'react'
interface ButtonProps { children: ReactNode variant?: 'primary' | 'secondary' type?: 'button' | 'submit' disabled?: boolean}
export function Button({ children, variant = 'primary', ...props }: ButtonProps) { const className = `btn btn-${variant}` return ( <button className={className} {...props}> {children} </button> )}Callouts
Use the Callout component to highlight important information in your posts: