Introduction
Getting Started
An opinionated Prettier plugin for Laravel Blade templates.
#Installation
Requires Node.js 18 or newer.
Install Prettier and the plugin in your project:
1npm i -D prettier prettier-plugin-blade@^3
Optional integrations:
1npm i -D @prettier/plugin-php prettier-plugin-tailwindcss
#Migration
Chisel v3 (prettier-plugin-blade) is a ground-up rewrite. Expect output changes compared to previous versions.
If you rely on previous versions, you should specify the exact version you'd like to use in your package.json.
#Quick Start
Create or update your .prettierrc:
1{
2 "plugins": [
3 "prettier-plugin-blade"
4 ],
5 "overrides": [
6 {
7 "files": ["*.blade.php"],
8 "options": {
9 "parser": "blade"
10 }
11 }
12 ]
13}
Format:
1npx prettier --write "resources/views/**/*.blade.php"
#CLI Flags
You can pass Blade plugin options directly to the Prettier CLI as kebab-case flags:
1npx prettier "resources/views/**/*.blade.php" \
2 --write \
3 --plugin prettier-plugin-blade \
4 --plugin @prettier/plugin-php \
5 --parser blade \
6 --blade-php-formatting safe \
7 --blade-php-formatting-targets echo \
8 --blade-php-formatting-targets directiveArgs \
9 --blade-component-prefixes x \
10 --blade-component-prefixes flux \
11 --blade-directive-arg-spacing space \
12 --blade-echo-spacing tight
Notes:
- Use kebab-case in CLI flags (for example
bladePhpFormatting->--blade-php-formatting). - Load
@prettier/plugin-phpwhen usingbladePhpFormatting: "safe"from the CLI. - Array options use repeated flags in CLI (for example:
--blade-inline-intent-elements p --blade-inline-intent-elements svg --blade-inline-intent-elements svg:*). bladeDirectiveCaseMaptakes a JSON object string when passed via CLI, but shell quoting is easy to get wrong. Prefer setting it in.prettierrc.
#PHP Formatting
To format embedded PHP fragments inside Blade, install @prettier/plugin-php and include it in plugins:
1{
2 "plugins": [
3 "prettier-plugin-blade",
4 "@prettier/plugin-php"
5 ],
6 "overrides": [
7 {
8 "files": ["*.blade.php"],
9 "options": {
10 "parser": "blade",
11 "bladePhpFormatting": "safe"
12 }
13 }
14 ]
15}
Notes:
- Without
@prettier/plugin-php, the formatter still works. It falls back gracefully and leaves PHP fragments unchanged. bladePhpFormattingmodes documented here:"off","safe".
#Enable Tailwind CSS Class Sorting
Install the Tailwind CSS plugin and include it in plugins:
1{
2 "plugins": [
3 "prettier-plugin-blade",
4 "prettier-plugin-tailwindcss"
5 ],
6 "overrides": [
7 {
8 "files": ["*.blade.php"],
9 "options": {
10 "parser": "blade"
11 }
12 }
13 ]
14}
#VS Code Setup
- Install the
Prettier - Code formatterextension (esbenp.prettier-vscode). - Ensure your project has local
devDependenciesfor Prettier and this plugin. - Add workspace settings in
.vscode/settings.json:
1{
2 "editor.formatOnSave": true,
3 "editor.defaultFormatter": "esbenp.prettier-vscode",
4 "prettier.requireConfig": true,
5 "files.associations": {
6 "*.blade.php": "blade"
7 },
8 "[blade]": {
9 "editor.defaultFormatter": "esbenp.prettier-vscode"
10 }
11}
#Options
#Blade Plugin Options
| Option | Type | Default | Values |
|---|---|---|---|
bladePhpFormatting |
choice |
"safe" |
"off", "safe", "aggressive" |
bladePhpFormattingTargets |
string[] |
["directiveArgs", "echo", "phpBlock", "phpTag"] |
echo, directiveArgs, phpBlock, phpTag; use [] (or CLI none) to disable all |
bladeSyntaxPlugins |
string[] |
["statamic"] |
plugin names (for example ["statamic"]) |
bladeDirectiveCase |
choice |
"preserve" |
"preserve", "canonical", "lower" |
bladeDirectiveCaseMap |
string |
"" |
JSON object string, e.g. {"disk":"Disk"} |
bladeDirectiveArgSpacing |
choice |
"space" |
"preserve", "none", "space" |
bladeDirectiveBlockStyle |
choice |
"preserve" |
"preserve", "inline-if-short", "multiline" |
bladeBlankLinesAroundDirectives |
choice |
"preserve" |
"preserve", "always" |
bladeEchoSpacing |
choice |
"preserve" |
"preserve", "space", "tight" |
bladeSlotClosingTag |
choice |
"canonical" |
"canonical", "preserve" |
bladeInlineIntentElements |
string[] |
["p", "svg", "svg:*"] |
elements and namespace wildcards |
bladeComponentPrefixes |
string[] |
["x", "s", "statamic", "flux", "livewire", "native"] |
component prefixes |
bladeInsertOptionalClosingTags |
boolean |
false |
true, false |
bladeKeepHeadAndBodyAtRoot |
boolean |
true |
true, false |
bladePhpFormattingTargets aliases supported in each array entry:
echoes->echodirective-args,directive_args->directiveArgsphp-block,php_block->phpBlockphp-tag,php_tag->phpTag
bladeComponentPrefixes behavior:
- Bare prefix tokens expand to both Blade component separator forms:
x->x-,x:widget->widget-,widget:
- Explicit separator tokens are preserved as-is:
x-matches only dash form tagsx:matches only colon form tags
bladeInlineIntentElements SVG behavior:
svgkeeps single-line<svg>...</svg>container intent when the source is inline.svg:*keeps inline attribute and style intent for SVG namespace elements such as<path>and<line>.- Remove one or both entries to opt out of those SVG-specific inline layouts.
#bladeBlankLinesAroundDirectives
This option controls blank lines between directive branches inside a structured directive block.
Examples of branch separators this option affects:
@if ... @else ... @endif@switch ... @case ... @default ... @endswitch@section ... @endsection
Primary scope:
- It decides how much vertical space to print between one branch and the next branch marker.
- In
preservemode it can also keep some existing blank lines between structured siblings inside a directive body when those blank lines were already present in source.
That means it can affect spacing before @else, @elseif, @endif, @case, @default, @endswitch, and similar closers/openers inside the same directive block.
Supported values:
"preserve"- Keeps an existing blank line between directive branches if one existed in the source.
- Otherwise prints a single newline between branches.
"always"- Always inserts a blank line between directive branches.
- In practice this means two line breaks between branches.
Example input:
1@if($x)
2<p>a</p>
3@else
4<p>b</p>
5@endif
With bladeBlankLinesAroundDirectives: "preserve":
1@if ($x)
2 <p>a</p>
3@else
4 <p>b</p>
5@endif
With bladeBlankLinesAroundDirectives: "always":
1@if ($x)
2 <p>a</p>
3
4@else
5 <p>b</p>
6
7@endif
Notes:
- This option is most visible when directive blocks print in multiline form.
- If a block is kept inline, there are no multiline branch separators for this option to manage.
- In
preservemode, some authored blank lines inside a directive body can also survive between structured siblings when the source already had them.
#Relevant Core Prettier Options
This plugin also respects standard Prettier options, including:
printWidthtabWidthuseTabssingleQuotesingleAttributePerLinebracketSameLineendOfLinehtmlWhitespaceSensitivity
#Example Full Config
1{
2 "plugins": [
3 "prettier-plugin-blade",
4 "@prettier/plugin-php",
5 "prettier-plugin-tailwindcss"
6 ],
7 "overrides": [
8 {
9 "files": ["*.blade.php"],
10 "options": {
11 "parser": "blade",
12 "htmlWhitespaceSensitivity": "css",
13 "bladePhpFormatting": "safe",
14 "bladePhpFormattingTargets": ["directiveArgs", "echo", "phpBlock", "phpTag"],
15 "bladeSyntaxPlugins": ["statamic"],
16 "bladeDirectiveCase": "preserve",
17 "bladeDirectiveArgSpacing": "space",
18 "bladeDirectiveBlockStyle": "preserve",
19 "bladeBlankLinesAroundDirectives": "preserve",
20 "bladeEchoSpacing": "space",
21 "bladeSlotClosingTag": "canonical",
22 "bladeInlineIntentElements": ["p", "svg", "svg:*"],
23 "bladeComponentPrefixes": ["x", "s", "statamic", "flux", "livewire", "native"],
24 "bladeInsertOptionalClosingTags": false,
25 "bladeKeepHeadAndBodyAtRoot": true
26 }
27 }
28 ]
29}
#Troubleshooting
#Tailwind CSS classes are not sorting
- Confirm
prettier-plugin-tailwindcssis installed. - Confirm it is listed in
plugins. - Confirm class values are static strings (not mixed with Blade interpolation).
#PHP formatting is not running
- Install
@prettier/plugin-php. - Set
bladePhpFormattingto"safe". - Ensure target is enabled in
bladePhpFormattingTargets.
#VS Code formats with wrong Prettier
- Use local project dependencies.
- Set
"prettier.requireConfig": true. - Set
"prettier.prettierPath"when needed.