{{ }}
Prints a PHP expression into a template, escaped through htmlspecialchars to prevent XSS.
{{ $expression }} {!! $expression !!}Parameters
| Parameter | Type | Description |
|---|---|---|
$expression | mixed | Any PHP expression — a variable, a property, a method call or a function call. Its result is cast to a string. |
Return value
stringThe evaluated expression rendered into the compiled view; {{ }} passes it through e() first, {!! !!} does not.
Errors
Echoing an object with no __toString() raises an Error, and an undefined variable raises a PHP warning inside the compiled view rather than in the .blade.php file.
Blade compiles {{ $name }} to <?php echo e($name); ?>, and e() runs PHP's htmlspecialchars. That makes it the default way to put anything on a page: comment bodies, query strings, names typed by users. You are not limited to variables — any PHP expression works, including function calls.
When to use the raw form
Use {!! $html !!} only for markup your own code produced — a rendered Markdown body, a mail template fragment, an HtmlString. Anything that passed through a request or a database column a user can write to must go through {{ }}.
Double encoding
Blade double encodes by default, so a stored & is rendered as &amp; and the reader sees the entity text. If your data already holds entities, call Blade::withoutDoubleEncoding() in the boot method of AppServiceProvider.
Braces that are not yours
Vue, Alpine and Handlebars also use curly braces. Prefix the expression with an @ — @{{ name }} — to make Blade strip the @ and leave the braces for the client. For a whole block, wrap it in @verbatim. The same trick escapes directives: @@if() renders as literal @if().
Example
<?php
use Illuminate\Support\Facades\Blade;
$comment = '<script>alert("xss")</script> & friends';
// Escaped: e() applies htmlspecialchars with ENT_QUOTES.
echo Blade::render('<p>{{ $comment }}</p>', ['comment' => $comment]);
// <p><script>alert("xss")</script> & friends</p>
// Raw: nothing is escaped, so the script tag becomes live HTML.
echo Blade::render('<p>{!! $comment !!}</p>', ['comment' => $comment]);
// <p><script>alert("xss")</script> & friends</p>When to use it
- Render a user-submitted comment body on a page without opening an XSS hole
- Print a Markdown-rendered article that is already trusted HTML with {!! !!}
- Hand a PHP array to a JavaScript bundle as a JSON.parse call
- Leave Vue or Alpine bindings untouched inside a Blade-rendered page
Frequently asked questions
What is the difference between {{ }} and {!! !!} in Blade?
{{ }} escapes its output through PHP's htmlspecialchars, while {!! !!} prints the value byte for byte. Use the escaped form for anything a user can influence; the raw form is only for HTML your application generated itself.
How do I stop Blade from double encoding HTML entities?
Call Blade::withoutDoubleEncoding() in the boot method of your AppServiceProvider. Blade and the e() helper double encode by default, so a stored & would otherwise render as &amp;.
How do I output Vue or Alpine curly braces from a Blade view?
Prefix the expression with an @, as in @{{ name }} — Blade removes the @ and leaves the braces for the JavaScript framework. Use @verbatim ... @endverbatim to exempt an entire block.
More examples
Keeping Alpine and Vue braces intact
The first expression is evaluated by Blade on the server. The second keeps its braces because the leading @ tells Blade to skip it and emit the braces verbatim, so Alpine can bind it in the browser. For a long block of client-side templating, wrap it in @verbatim instead of prefixing every line.
<?php
use Illuminate\Support\Facades\Blade;
$template = <<<'BLADE'
<div x-data="{ name: 'Sam' }">
Server: {{ $name }}
Client: @{{ name }}
</div>
BLADE;
echo Blade::render($template, ['name' => 'Samantha']);
// <div x-data="{ name: 'Sam' }">
// Server: Samantha
// Client: {{ name }}
// </div>Passing data into JavaScript safely
Js::from returns a JSON.parse statement whose argument has been escaped for inclusion inside HTML quotes, so an apostrophe or a </script> sequence in the data cannot terminate the script block. Plain {{ $config }} would fail (arrays cannot be cast to string) and {!! json_encode($config) !!} would leave the injection open.
<?php
use Illuminate\Support\Facades\Blade;
$template = <<<'BLADE'
<script>
var app = {{ Illuminate\Support\Js::from($config) }};
</script>
BLADE;
echo Blade::render($template, [
'config' => ['locale' => 'en', 'title' => "Bob's page"],
]);
// <script>
// var app = JSON.parse('...');
// </script>Double encoding of stored entities
Blade encodes the ampersand of an existing entity a second time, which is why legacy data that was HTML-encoded on the way into the database appears with visible & sequences. Turning double encoding off fixes the display globally, but it also means raw ampersands in new data are no longer re-encoded, so pick one convention for the whole application.
<?php
use Illuminate\Support\Facades\Blade;
// The column already holds an HTML entity.
echo Blade::render('{{ $company }}', ['company' => 'AT&T']);
// AT&amp;T -> the browser shows the literal text "AT&T"
// After calling Blade::withoutDoubleEncoding() in AppServiceProvider::boot(),
// the same view renders:
// AT&T -> the browser shows "AT&T"
Discussion