In Laravel, how do Blade's @fragment directive and a view's fragmentIf() method return only a course list for a partial-page request?
answer
- @fragment('name') ... @endfragment
- ->fragment('name') returns a string
- fragmentIf(condition, name) else full page
- the whole template still executes
- unknown name falls back to full page
basics
~10 sWrap the list in @fragment('course-list') ... @endfragment. Returning view(...)->fragment('course-list') renders the template but sends only that block, and fragmentIf($condition, 'course-list') does so only when the condition holds, otherwise the full page.
solid answer
~40 sA Blade **fragment** is a named block, `@fragment('course-list') ... @endfragment`, that prints inline during a normal render but is also captured by name. In the controller, `view('courses.index', [...])->fragment('course-list')` renders the view and returns just that block's HTML as a string, which is what partial-page tools such as htmx or Turbo want. `->fragmentIf($request->hasHeader('HX-Request'), 'course-list')` returns the fragment for those requests and the full page otherwise; `fragments([...])` and `fragmentsIf()` concatenate several. Two things to remember: the **entire template still executes**, layout included, and only the output is discarded, so it saves bytes, not work. And a mistyped fragment name is not an error; `fragment()` quietly falls back to returning the full page.
code
html · 12 lines<!-- resources/views/courses/index.blade.php -->
<x-layout>
<input name="q" hx-get="/courses" hx-target="#course-list">
@fragment('course-list')
<ul id="course-list">
@foreach ($courses as $course)
<li>{{ $course->name }}</li>
@endforeach
</ul>
@endfragment
</x-layout>go deeper
Recall the pair: @fragment('name') ... @endfragment in the template, ->fragment('name') or ->fragmentIf($condition, 'name') on the view in the controller.
Explain that fragment() renders the whole view and extracts the captured block, that it returns a string, and that the block still prints inline in a full render.
Call out the silent full-page fallback on a wrong name, and the wasted work when the page around the fragment is expensive; know when a dedicated partial is the better endpoint.
Judge whether one template serving both full and partial responses keeps the codebase simpler than separate partial views, given the rendering cost and the testing needed.
## The use case Hypermedia front-end tools such as **htmx** and **Turbo** request a page and swap only part of it into the DOM: a filtered course list, a table row, a form with its errors. Without help, the server either renders the whole page and lets the client cut out the piece, or maintains a separate partial template for that piece. **Blade fragments** let one template serve both the full page and the piece. ## Marking and returning a fragment 1. In the template, wrap the region in `@fragment('course-list') ... @endfragment`. During an ordinary render the block prints inline, exactly as if the directives were not there. 2. While rendering, Blade also captures the block's output under its name in the view factory. 3. In the controller, call `fragment()` on the view instead of returning the view itself: - `view('courses.index', $data)->fragment('course-list')` returns only that block. - `->fragmentIf($condition, 'course-list')` returns the block when the condition is true and the full rendered page when it is false. - `->fragments(['course-list', 'pagination'])` returns several blocks concatenated in the order you list them; with no argument it concatenates every fragment in the view. - `->fragmentsIf($condition, [...])` is the conditional version of `fragments()`. A typical condition is the header the client library sends, such as htmx's `HX-Request`: `fragmentIf($request->hasHeader('HX-Request'), 'course-list')`. ## What still runs The implementation matters for performance. `fragment()` does not compile or execute only the fragment: it calls the view's normal `render()` with a callback, and the callback picks the captured block out of the result. So: - the **whole template executes**, including any `@extends` layout rendered from the child's footer, every included partial, every component, and every view composer attached to those views; - lazy-loaded relationships or helper calls outside the fragment still run their queries; - only the **bytes sent** shrink. If a fragment request is hot and the rest of the page is expensive, move the expensive data behind conditions or into a dedicated partial view that the controller renders directly. ## Return type and failure modes | Call | Returns | |---|---| | `fragment('name')` | the captured block as a string | | `fragment('missing-name')` | the full rendered page, with no error | | `fragmentIf(false, 'name')` | the full rendered page | | `fragments()` with no argument | every fragment, concatenated | The second row is the trap. The view looks the name up among the captured fragments and, when it finds nothing, falls back to the whole rendered view. A typo in a fragment name therefore swaps an entire page, layout and all, into the middle of the DOM, and nothing is logged. A feature test that asserts the fragment response does *not* contain a layout-only string such as the page's `<title>` catches it. Because these methods return a **string**, not a view, you cannot chain more view methods after them; attach data before calling `fragment()`. ## When a fragment is the wrong tool - The page around the fragment is expensive and the partial endpoint is hot: a dedicated partial view rendered directly is cheaper. - The client needs JSON rather than HTML: return an API response instead of HTML. - The piece is reused across several pages: a Blade component or an included partial is easier to share than a fragment tied to one template. - The interaction is stateful and component-shaped: a Livewire component may fit better than hand-wired partial requests. ## Fragments and layouts Fragments work inside template inheritance: a `@fragment` inside the child's `@section('content')` is captured when the child's section runs, before the layout renders. They also work inside a page wrapped in a layout component, because the slot content runs as part of the render. Fragment names should be unique within a render; a second fragment with the same name replaces the first one's captured output.
- Does returning ->fragment('course-list') from a Blade view avoid running the queries the rest of the page needs?No. `fragment()` renders the whole view through its normal `render()` and then picks out the captured block, so the layout, partials, components and their view composers all execute. Only the response body shrinks. For a hot partial endpoint with an expensive page around it, render a dedicated partial view or guard the costly parts.
- What happens when a Blade view's fragment() is called with a name no @fragment in the template uses?It returns the full rendered page. The lookup for the captured fragment yields null, and the view's render falls back to its complete contents when the callback returns null. No exception is thrown, so a typo shows up as an entire page swapped into the DOM. A feature test that asserts the layout's markup is absent catches it.
saying these in an interview costs you the question
- fragment() compiles and runs only the code between @fragment and @endfragment
- An unknown fragment name makes fragment() throw an exception
- @fragment content is hidden during a normal full-page render
- fragment() returns a View you can keep chaining with() onto
- fragmentIf() returns an empty response when its condition is false