spatie/shiki-php
Use Shiki syntax highlighting from PHP. Highlight code snippets with editor-quality themes and 100+ languages, plus Antlers and Blade. Works great with Laravel via spatie/laravel-markdown and CommonMark through a companion extension.
Install the package:
composer require spatie/shiki-php
Install Node.js dependencies (Node 20+ required):
npm install shiki
or with Yarn:
yarn add shiki
First usage (highlight PHP code):
use Spatie\ShikiPhp\Shiki;
echo Shiki::highlight(
code: '<?php echo "Hello World"; ?>',
language: 'php',
theme: 'github-light'
);
spatie/laravel-markdown for syntax-highlighted Markdown.Basic Highlighting:
$highlighted = Shiki::highlight(
code: $codeString,
language: 'php', // or 'javascript', 'blade', etc.
theme: 'github-dark'
);
<pre><code> block with Shiki’s styling.Line-Specific Styling:
Shiki::highlight(
code: $code,
language: 'php',
highlightLines: [3, '5-7'], // Highlight lines 3, 5-7
addLines: [1], // Mark line 1 as "added"
deleteLines: [4], // Mark line 4 as "deleted"
focusLines: [2] // Focus line 2
);
.shiki-line-highlighted, .shiki-line-added, etc.Dynamic Language/Themes:
$languages = Shiki::getAvailableLanguages(); // Array of supported languages
$themes = Shiki::getAvailableThemes(); // Array of supported themes
if (Shiki::languageIsAvailable('rust')) {
$highlighted = Shiki::highlight(code: $code, language: 'rust');
}
Laravel Blade:
@php
$highlighted = \Spatie\ShikiPhp\Shiki::highlight(
code: '{{ $code }}',
language: 'blade',
theme: 'vscode-dark-plus'
);
@endphp
{!! $highlighted !!}
Markdown Parsing (via spatie/laravel-markdown):
use Spatie\Markdown\MarkdownRenderer;
$renderer = new MarkdownRenderer();
$renderer->useShikiHighlighter(); // Auto-highlights code blocks
echo $renderer->toHtml($markdownContent);
API Responses:
return response()->json([
'code' => $highlightedHtml,
'language' => 'php',
'theme' => 'github-light'
]);
Caching: Cache highlighted output for static content (e.g., documentation):
$cacheKey = "shiki_{$language}_{$theme}_{md5($code)}";
$highlighted = Cache::remember($cacheKey, now()->addHours(1), function() use ($code, $language, $theme) {
return Shiki::highlight(code: $code, language: $language, theme: $theme);
});
Custom Themes:
Shiki::highlight(
code: $code,
theme: __DIR__ . '/path/to/custom-theme.json'
);
Dual Themes (Shiki v4+):
Shiki::highlight(
code: $code,
theme: ['github-dark', 'dracula'] // Fallback themes
);
Large Code Blocks:
Avoid proc_open() errors by passing code via stdin (handled automatically in v2.3.3+).
Node.js Path Issues:
sudo ln -s ~/.nvm/versions/node/v20.x.x/bin/node /usr/local/bin/node
\Spatie\ShikiPhp\Shiki::getNodePath();
Language/Theme Availability:
if (!Shiki::languageIsAvailable('custom-lang')) {
throw new \InvalidArgumentException("Language not supported");
}
Large Code Blocks:
proc_open(): posix_spawn() failed: Argument list too longspatie/shiki-php v2.3.3+ (uses stdin for large inputs).Blade/Antlers Syntax:
CSS Conflicts:
.shiki pre {
background: transparent !important;
}
Verbose Output: Enable debug mode to see Node command execution:
\Spatie\ShikiPhp\Shiki::setDebug(true);
Check Node Version:
$nodeVersion = \Spatie\ShikiPhp\Shiki::getNodeVersion();
if (version_compare($nodeVersion, '20.0.0', '<')) {
throw new \RuntimeException("Node 20+ required");
}
getAvailableLanguages() is lightweight.Custom Renderer Scripts: Override the default Node script (advanced):
\Spatie\ShikiPhp\Shiki::setRendererScript(__DIR__ . '/custom-renderer.js');
Post-Processing: Modify output HTML with a closure:
$highlighted = Shiki::highlight($code, $language, $theme)
->replace('<pre', '<pre class="custom-class"');
Event Hooks (via Service Provider):
Shiki::macro('afterHighlight', function ($html, $code, $options) {
// Modify $html before returning
return $html;
});
| Issue | Solution |
|---|---|
| Blank output | Ensure shiki is installed via npm/yarn. |
| Unsupported language/theme | Check getAvailableLanguages()/getAvailableThemes(). |
| Slow rendering | Cache results or upgrade Node version. |
| CSS not applying | Inspect inline styles or override with !important. |
Argument list too long error |
Upgrade to v2.3.3+ or split code into chunks. |
github-dark/github-light for consistency with GitHub..shiki pre {
counter-reset: line;
}
.shiki .line {
counter-increment: line;
}
.shiki .line::before {
content: counter(line);
display: inline-block;
width: 2em;
margin-right: 1em;
text-align: right;
}
How can I help you explore Laravel packages today?