A Shiki transformer that hides marked lines from rendered code blocks while keeping them in the source.
Hide boilerplate (imports, setup, autoloading) that is necessary for execution but distracting for readers.
npm install shiki-hide-linesMark single lines with // [!code hide] or # [!code hide]:
<?php // [!code hide]
declare(strict_types=1); // [!code hide]
require_once 'vendor/autoload.php'; // [!code hide]
use App\Models\User; // [!code hide]
$user = User::find(1);
echo $user->name;import os # [!code hide]
from pathlib import Path # [!code hide]
print(Path.home())Rendered output shows only the meaningful lines.
Use block markers to hide ranges:
// [!code hide:start]
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
// [!code hide:end]
createApp(App).use(router).mount('#app')# [!code hide:start]
version: '3.8'
services:
# [!code hide:end]
web:
image: nginx:alpine
ports:
- '8080:80'The comment marker adapts to the language:
| Marker | Languages |
|---|---|
// |
PHP, JavaScript, TypeScript, Go, Rust, Java, C |
# |
Python, Ruby, Bash, YAML, Perl, Dockerfile, Elixir |
-- |
SQL, Lua, Haskell, Elm |
% |
LaTeX, TeX, Erlang |
; |
Lisp, Scheme, Clojure, ASM |
Fully Hidden (default) — marked lines are completely removed from output:
import { codeToHtml } from 'shiki'
import { transformerHideLines } from 'shiki-hide-lines'
const html = await codeToHtml(code, {
lang: 'php',
theme: 'github-dark',
transformers: [transformerHideLines()]
})Revealable — marked lines are collapsed behind a clickable placeholder:
transformerHideLines({ reveal: true })In reveal mode, a ··· N hidden lines placeholder appears. Clicking it expands the hidden lines and changes the text to ▲ N hidden lines. Clicking again collapses them back.
Customize the collapsed and expanded placeholder text:
String template — use {count} for the line count:
transformerHideLines({
reveal: true,
summaryTemplate: '▶ {count} lines collapsed',
expandedSummaryTemplate: '▼ {count} lines shown'
})
// Collapsed: ▶ 3 lines collapsed
// Expanded: ▼ 3 lines shownFunction — full control for i18n or pluralization:
transformerHideLines({
reveal: true,
summaryTemplate: (count) =>
count === 1 ? '1 ligne masquée' : `${count} lignes masquées`,
expandedSummaryTemplate: (count) =>
count === 1 ? '▲ 1 ligne' : `▲ ${count} lignes`
})Change the marker keyword (default: hide):
transformerHideLines({ marker: 'hidden' })
// Uses: // [!code hidden] and // [!code hidden:start] / // [!code hidden:end]// .vitepress/config.ts
import { transformerHideLines } from 'shiki-hide-lines'
export default defineConfig({
markdown: {
codeTransformers: [
transformerHideLines({ reveal: true })
]
}
})// astro.config.mjs
import { transformerHideLines } from 'shiki-hide-lines'
export default defineConfig({
markdown: {
shikiConfig: {
transformers: [transformerHideLines()]
}
}
})// nuxt.config.ts
import { transformerHideLines } from 'shiki-hide-lines'
export default defineNuxtConfig({
content: {
highlight: {
transformers: [transformerHideLines()]
}
}
})Reveal mode requires CSS and a small client-side script for the toggle interaction.
Import the default stylesheet:
import 'shiki-hide-lines/style.css'Or add it to your CSS manually. The styles use these classes:
| Class | Element | Description |
|---|---|---|
has-hidden-lines |
<pre> |
Code block contains hidden lines |
hidden-line |
<span class="line"> |
A hidden line |
hidden-lines-summary |
<span> |
Clickable placeholder (role="button") |
hidden-lines-revealed |
<pre> |
Toggled to expanded state |
hidden-lines-collapsed-text |
<span> |
Text shown when collapsed |
hidden-lines-expanded-text |
<span> |
Text shown when expanded |
The default styles respect --vp-code-tab-text-color and --vp-c-brand CSS custom properties for theme compatibility.
The toggle requires event delegation for click and keyboard interaction. Choose one:
Option A — Inline script (SSG/SSR sites):
import { getToggleScript } from 'shiki-hide-lines'
// Inject into your page <head> or layout
const script = `<script>${getToggleScript()}</script>`Option B — Direct import (SPA/client-side, e.g. VitePress):
import { setupHiddenLinesToggle } from 'shiki-hide-lines'
setupHiddenLinesToggle()Both options register click and keyboard (Enter/Space) handlers with full ARIA support.
Reveal mode follows the ARIA disclosure pattern:
- Summary elements have
role="button"andtabindex="0"for keyboard access aria-expandedreflects the current toggle statearia-labeldescribes the action (e.g. "Toggle 3 hidden lines")- Enter and Space keys trigger the toggle
- Focus indicator appears on keyboard navigation (
:focus-visible)
function transformerHideLines(options?: HideLinesOptions): ShikiTransformer| Option | Type | Default | Description |
|---|---|---|---|
reveal |
boolean |
false |
Enable reveal mode with clickable placeholders |
marker |
string |
'hide' |
The marker keyword in [!code <marker>] |
summaryTemplate |
string | (count: number) => string |
'··· N hidden line(s)' |
Customize collapsed placeholder text. Use {count} in strings |
expandedSummaryTemplate |
string | (count: number) => string |
'▲ N hidden line(s)' |
Customize expanded placeholder text. Use {count} in strings |
| Export | Description |
|---|---|
transformerHideLines |
The Shiki transformer factory |
getToggleScript |
Returns toggle script as a string (for inline injection) |
setupHiddenLinesToggle |
Registers click and keyboard handlers (for SPA use) |
HideLinesOptions |
TypeScript options interface |