Server-side syntax highlighting for Grav CMS using Phiki, a PHP port of Shiki that uses TextMate grammars and VS Code themes.
- Server-side rendering - No JavaScript required for syntax highlighting
- Automatic theme switching - Detects light/dark mode and switches themes automatically
- 70+ themes - All VS Code themes including GitHub, Dracula, Nord, Monokai, and more
- 200+ languages - Full TextMate grammar support for accurate highlighting
- Markdown processing - Automatically highlights fenced code blocks in markdown
- Line numbers - Optional line number gutter with custom starting line
- Line highlighting - Highlight specific lines to draw attention
- Line focus - Dim non-focused lines to emphasize important code
- Line wrapping - Wrap long lines instead of horizontal scrolling
- Title/filename display - Show filename or custom title in the header
- Minimal mode - Hide header for clean, minimal appearance
- Code groups - Tabbed interface for multiple code examples with sync support
- Copy the
codeshfolder touser/plugins/ - Run
composer installin the plugin directory - Enable the plugin in Admin or via
user/config/plugins/codesh.yaml
- PHP 8.1+
- Grav 1.7+
- shortcode-core plugin 5.0+
Use BBCode-style parameter for the language:
[codesh=php]
<?php
echo "Hello, World!";
[/codesh]Or use the lang attribute:
[codesh lang="javascript"]
const greeting = "Hello, World!";
console.log(greeting);
[/codesh]Fenced code blocks in markdown are automatically highlighted:
console.log("Hello, World!");This feature can be disabled via the process_markdown config option.
For compatibility with markdown editors, you can wrap standard fenced code blocks:
[codesh]
```php
<?php
echo "Hello, World!";[/codesh]
### Line Numbers
Enable line numbers with the `line-numbers` attribute:
```markdown
[codesh lang="python" line-numbers="true"]
def greet(name):
return f"Hello, {name}!"
print(greet("World"))
[/codesh]
Start from a specific line number:
[codesh lang="python" line-numbers="true" start="10"]
def greet(name):
return f"Hello, {name}!"
[/codesh]Highlight specific lines using highlight or hl:
[codesh lang="javascript" highlight="2,4-6"]
const a = 1;
const b = 2; // highlighted
const c = 3;
const d = 4; // highlighted
const e = 5; // highlighted
const f = 6; // highlighted
const g = 7;
[/codesh]Syntax: Single lines (1,3,5), ranges (2-4), or combined (1,3-5,8).
Focus on specific lines (dims non-focused lines):
[codesh lang="javascript" focus="3-5"]
function example() {
// setup code
const important = true; // focused
doSomething(important); // focused
return important; // focused
// cleanup code
}
[/codesh]Show a filename or custom title in the header:
[codesh lang="php" title="src/Controller/UserController.php"]
<?php
namespace App\Controller;
class UserController extends AbstractController
{
// ...
}
[/codesh]Hide the language badge while keeping the header:
[codesh lang="bash" hide-lang="true"]
npm install
npm run build
[/codesh]Hide the entire header for a super minimal look:
[codesh lang="javascript" hide-header="true"]
const minimal = true;
[/codesh]By default, line wrapping is enabled globally (configurable in plugin settings). Long lines will wrap to the next line instead of scrolling horizontally. Line numbers stay aligned with wrapped content.
Override the global setting for a specific code block:
[codesh lang="javascript" wrap="false"]
// This block will scroll horizontally regardless of global setting
const veryLongLine = "This line is very long and will scroll horizontally instead of wrapping to the next line";
[/codesh]Force wrapping on even if globally disabled:
[codesh lang="javascript" wrap="true"]
// This block will wrap regardless of global setting
[/codesh]Override the automatic theme for a specific code block:
[codesh lang="rust" theme="dracula"]
fn main() {
println!("Hello, Rustaceans!");
}
[/codesh]Add custom classes for additional styling:
[codesh lang="html" class="my-custom-class"]
<div>Hello</div>
[/codesh]Display multiple code examples in a tabbed interface. Use the title attribute on each [codesh] block to set the tab label.
[codesh-group]
[codesh lang="javascript" title="helloWorld.js"]
console.log("Hello World");
[/codesh]
[codesh lang="python" title="hello_world.py"]
print("Hello World")
[/codesh]
[codesh lang="java" title="HelloWorld.java"]
System.out.println("Hello World");
[/codesh]
[/codesh-group]Use the sync attribute to synchronize tab selection across multiple code groups. When a tab is selected in one group, all groups with the same sync key will switch to the matching tab.
[codesh-group sync="lang"]
[codesh lang="javascript" title="JavaScript"]
const name = "World";
[/codesh]
[codesh lang="python" title="Python"]
name = "World"
[/codesh]
[/codesh-group]
Some text in between...
[codesh-group sync="lang"]
[codesh lang="javascript" title="JavaScript"]
console.log(`Hello, ${name}!`);
[/codesh]
[codesh lang="python" title="Python"]
print(f"Hello, {name}!")
[/codesh]
[/codesh-group]Tab selections are also persisted in localStorage, so they survive page reloads.
In user/config/plugins/codesh.yaml:
enabled: true
active: true
theme_dark: github-dark # Theme for dark mode
theme_light: github-light # Theme for light mode
show_line_numbers: false # Default line numbers setting
line_wrap: true # Wrap long lines (default: true)
process_markdown: true # Auto-highlight markdown code blocksCodesh automatically detects your theme's light/dark mode setting:
- System mode: Uses CSS variable switching for instant theme changes
- Light mode: Uses the
theme_lightsetting - Dark mode: Uses the
theme_darksetting
When you specify an explicit theme attribute on a code block, that theme is used regardless of mode.
The plugin includes a full-featured theme management system in the Grav Admin panel.
The plugin settings page features a custom theme picker for selecting dark and light themes:
- Visual Preview - Each theme shows a live syntax-highlighted code preview
- Search - Filter themes by name
- Filters - Filter by All, Dark, Light, or Custom themes
- One-Click Selection - Click any theme card to select it
Access the full theme gallery via Admin > CodeSh Themes in the sidebar. This provides a read-only view of all available themes with full-size previews.
Import VS Code compatible themes directly from JSON files:
- Click the Import button in the theme picker modal
- Select a
.jsontheme file (VS Code theme format) - The theme is automatically:
- Validated for required structure
- Normalized (short hex colors like
#fffare expanded to#ffffff) - Type-detected (light/dark) if not specified
- Saved to
user/data/codesh/themes/
Imported themes appear with a Custom badge and can be filtered using the Custom filter.
Custom/imported themes can be deleted:
- Click the red trash icon on any custom theme card
- Confirm the deletion in the dialog
Note: Built-in themes cannot be deleted.
- Built-in themes:
user/plugins/codesh/themes/ - Custom themes:
user/data/codesh/themes/
| Theme | Theme | Theme |
|---|---|---|
andromeeda |
aurora-x |
ayu-dark |
catppuccin-frappe |
catppuccin-macchiato |
catppuccin-mocha |
dark-plus |
dracula |
dracula-soft |
everforest-dark |
github-dark |
github-dark-default |
github-dark-dimmed |
github-dark-high-contrast |
gruvbox-dark-hard |
gruvbox-dark-medium |
gruvbox-dark-soft |
houston |
kanagawa-dragon |
kanagawa-wave |
laserwave |
material-theme |
material-theme-darker |
material-theme-ocean |
material-theme-palenight |
min-dark |
monokai |
night-owl |
nord |
one-dark-pro |
plastic |
poimandres |
red |
rose-pine |
rose-pine-moon |
slack-dark |
solarized-dark |
synthwave-84 |
tokyo-night |
vesper |
vitesse-black |
vitesse-dark |
| Theme | Theme | Theme |
|---|---|---|
catppuccin-latte |
everforest-light |
github-light |
github-light-default |
github-light-high-contrast |
gruvbox-light-hard |
gruvbox-light-medium |
gruvbox-light-soft |
kanagawa-lotus |
light-plus |
material-theme-lighter |
min-light |
one-light |
rose-pine-dawn |
slack-ochin |
snazzy-light |
solarized-light |
vitesse-light |
Language aliases are supported (e.g., js for javascript, py for python, sh for bash).
abap, actionscript-3, ada, apex, apl, applescript, ara, asm, awk, ballerina, bat, berry, bsl, c, cadence, cairo, clarity, clojure, cobol, coffee, common-lisp, coq, cpp, crystal, csharp, d, dart, dream-maker, elixir, elm, emacs-lisp, erlang, fennel, fish, fortran-fixed-form, fortran-free-form, fsharp, gdscript, genie, gleam, go, groovy, hack, haskell, haxe, hy, imba, java, javascript, jison, julia, kotlin, lean, llvm, logo, lua, luau, matlab, mojo, move, nextflow, nim, nix, nushell, objective-c, objective-cpp, ocaml, pascal, perl, php, pkl, plsql, polar, powershell, prolog, puppet, purescript, python, qml, r, racket, raku, razor, rel, riscv, ruby, rust, sas, scala, scheme, sdbl, shellscript, smalltalk, solidity, splunk, sql, stata, swift, system-verilog, systemd, talonscript, tcl, terraform, typescript, typst, v, vala, vb, verilog, vhdl, viml, vyper, wasm, wenyan, wgsl, wolfram, zenscript, zig
angular-expression, angular-html, angular-inline-style, angular-inline-template, angular-let-declaration, angular-template-blocks, angular-template, angular-ts, antlers, astro, blade, css, edge, erb, es-tag-css, es-tag-glsl, es-tag-html, es-tag-sql, es-tag-xml, glimmer-js, glimmer-ts, graphql, haml, handlebars, html, html-derivative, http, hurl, jinja, jinja-html, jsx, less, liquid, marko, mdc, mdx, postcss, pug, sass, scss, stylus, svelte, templ, ts-tags, tsx, twig, vue, vue-directives, vue-html, vue-interpolations, vue-sfc-style-variable-injection, vue-vine, wikitext, xml, xsl
beancount, bibtex, bicep, cmake, codeowners, codeql, csv, cue, cypher, dax, desktop, diff, docker, dotenv, fluent, gdresource, gdshader, gherkin, git-commit, git-rebase, gnuplot, hcl, hjson, hxml, ini, json, json5, jsonc, jsonl, jsonnet, jssm, kdl, kusto, log, make, narrat, nginx, po, powerquery, prisma, proto, qmldir, qss, reg, regexp, rosmsg, rst, sparql, ssh-config, tasl, toml, tsv, turtle, typespec, wit, yaml
apache, asciidoc, latex, maml, markdown, markdown-vue, tex, txt
glsl, hlsl, shaderlab
| Attribute | Description | Example |
|---|---|---|
lang |
Programming language | lang="php" |
theme |
Override color theme | theme="dracula" |
line-numbers |
Show line numbers | line-numbers="true" |
start |
Starting line number | start="10" |
highlight / hl |
Lines to highlight | highlight="1,3-5" |
focus |
Lines to focus | focus="2-4" |
title |
Filename or title in header | title="config.yaml" |
hide-lang |
Hide the language badge | hide-lang="true" |
hide-header |
Hide the header bar | hide-header="true" |
wrap |
Override line wrapping | wrap="false" |
class |
Additional CSS class | class="my-class" |
The plugin provides CSS classes for styling:
.codesh-block- Main container.codesh-block.no-header- Container without header.codesh-block.has-highlights- Container with highlighted lines.codesh-block.has-focus- Container with focused lines.codesh-block.codesh-line-wrap- Container with line wrapping enabled.codesh-dual-theme- Container using CSS variable theme switching
.codesh-header- Header bar.codesh-lang- Language badge.codesh-title- Title/filename display.codesh-copy- Copy button.codesh-copy.copied- Copy button after successful copy
.codesh-code- Code wrapper.codesh-block pre- Pre element.codesh-block .line- Each line of code.codesh-block .line.highlight- Highlighted lines.codesh-block .line.focus- Focused lines.codesh-block .line-number- Line number elements
The plugin uses Tailwind-style dark mode with .dark ancestor:
/* Light mode (default) */
.codesh-block { ... }
/* Dark mode */
.dark .codesh-block { ... }MIT License - see LICENSE for details.