Product Quick View
Quick-view dialog panels — a compact modal-style product card with image, pricing, rating and add-to-cart.
Preview
@props([
'name' => 'Aero Knit Runner',
'brand' => 'Atlas Athletics',
'badge' => 'New arrival',
'price' => '$148',
'compareAtPrice' => '$185',
'rating' => 4.5,
'reviewCount' => 312,
'description' => 'A breathable engineered-knit upper over a responsive foam midsole — built for daily miles and easy enough to wear straight off the run.',
'sizes' => null,
'selectedSize' => '9',
'detailsHref' => '#',
'closeHref' => '#',
'imageAlt' => 'Aero Knit Runner shown from the side',
])
@php
$sizes ??= ['7', '8', '9', '10', '11', '12'];
@endphp
<section {{ $attributes->merge(['class' => 'flex min-h-svh items-center justify-center bg-muted/40 px-4 py-12 text-foreground']) }}>
<x-ui.card
role="dialog"
aria-modal="true"
aria-label="{{ __('Product quick view') }}"
class="relative w-full max-w-3xl overflow-hidden rounded-lg border border-border bg-card p-0 shadow-xl"
>
{{-- Close (top end) --}}
<x-ui.button
:href="$closeHref"
variant="ghost"
size="icon"
class="absolute end-3 top-3 z-10 size-9 rounded-full text-muted-foreground hover:text-foreground"
aria-label="{{ __('Close quick view') }}"
>
<svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M18 6 6 18" />
<path d="m6 6 12 12" />
</svg>
</x-ui.button>
<div class="grid grid-cols-1 gap-0 sm:grid-cols-2">
{{-- Image (left) --}}
<div class="relative aspect-square w-full overflow-hidden bg-muted">
@if ($badge)
<x-ui.badge class="absolute start-3 top-3 z-10 shadow-sm">{{ __($badge) }}</x-ui.badge>
@endif
<svg
class="size-full text-muted-foreground/40"
viewBox="0 0 200 200"
fill="none"
role="img"
aria-label="{{ __($imageAlt) }}"
>
<rect width="200" height="200" fill="currentColor" fill-opacity="0.08" />
<path
d="M28 132c14-6 22-18 30-30 6-9 11-16 21-16 7 0 11 5 18 9 6 3 13 4 22 4 14 0 24 7 33 16l20 21H28v-4Z"
fill="currentColor"
fill-opacity="0.55"
/>
<circle cx="70" cy="74" r="9" fill="currentColor" fill-opacity="0.5" />
</svg>
</div>
{{-- Details (right) --}}
<div class="flex flex-col gap-4 p-6 sm:p-8">
<div class="flex flex-col gap-2 pe-8">
@if ($brand)
<p class="text-sm font-semibold uppercase tracking-wide text-muted-foreground">{{ __($brand) }}</p>
@endif
<h2 class="text-pretty text-xl font-semibold leading-tight tracking-tight sm:text-2xl">{{ __($name) }}</h2>
</div>
<div class="flex items-center gap-4">
<span class="text-xl font-bold tracking-tight">{{ $price }}</span>
@if ($compareAtPrice)
<span class="text-base text-muted-foreground line-through">{{ $compareAtPrice }}</span>
@endif
</div>
<div class="flex items-center gap-2">
<x-ui.rating :value="$rating" size="sm" read-only />
<span class="text-sm text-muted-foreground">
{{ number_format((float) $rating, 1) }}
({{ trans_choice('{0}No reviews|{1}:count review|[2,*]:count reviews', $reviewCount, ['count' => number_format($reviewCount)]) }})
</span>
</div>
<p class="line-clamp-2 text-pretty text-sm leading-relaxed text-muted-foreground">
{{ __($description) }}
</p>
<x-ui.separator class="my-2" />
{{-- Size selector --}}
<div class="flex flex-col gap-2">
<span class="text-sm font-medium text-foreground" aria-hidden="true">{{ __('Size') }}</span>
<x-ui.option-group
name="size"
:options="$sizes"
:selected="$selectedSize"
size="sm"
:label="__('Size')"
/>
</div>
{{-- Quantity --}}
<div class="flex flex-col gap-2">
<span class="text-sm font-medium text-foreground" aria-hidden="true">{{ __('Quantity') }}</span>
<x-ui.number-field
variant="stepper"
size="md"
:value="1"
:min="1"
:max="10"
:label="__('Quantity')"
class="w-fit"
/>
</div>
<div class="mt-2 flex flex-col gap-4">
<x-ui.button type="button" size="lg" class="w-full">
<svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="8" cy="21" r="1" />
<circle cx="19" cy="21" r="1" />
<path d="M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12" />
</svg>
{{ __('Add to cart') }}
</x-ui.button>
<a href="{{ $detailsHref }}" class="inline-flex items-center justify-center gap-2 text-sm font-medium text-link hover:underline">
{{ __('View full details') }}
<svg class="size-4 rtl:-scale-x-100" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M5 12h14" />
<path d="m12 5 7 7-7 7" />
</svg>
</a>
</div>
</div>
</div>
</x-ui.card>
</section>
Installation
php artisan ui:add blocks/product-quick-view-modal
Registry contract
Install confidence
php artisan ui:add blocks/product-quick-view-modal
writes only the generated targets below. The CLI validates each file hash before writing and
prompts before replacing local changes unless --force is used.
- Version
- 1.1.2
- License
- open
- Stability
- stable
- Contract
- v1
- Foundation
- ≥ 1.0.0
| Type | Generated target |
|---|---|
| blade | resources/views/blocks/product-quick-view-modal.blade.php |
Registry dependencies
Package dependencies
composer: jml/brok:^0.2
Use with AI
A brief for your coding agent: what the block is, the install command, how to render it, its props and the rules. Copy it, or open a prompt about this block in an assistant.
# Brok UI block: Product Quick View (`product-quick-view-modal`)
A centered quick-view dialog panel on a muted backdrop with a top-end close button, a square product image on the left, and details on the right: title, badge, price, rating, description, size selector, quantity stepper, add-to-cart button, and a view-full-details link.
Brok UI is a Laravel Blade registry. `ui:add` copies this block into the app as plain Blade the app owns; it composes installed `<brok:*>` primitives and semantic design tokens.
## Install
```bash
php artisan ui:add blocks/product-quick-view-modal
```
## Render it
```blade
<x-blocks.product-quick-view-modal />
```
## Props
- `name` (string, default `Aero Knit Runner`) — Product name shown as the dialog heading.
- `brand` (string, default `Atlas Athletics`) — Brand label shown above the product name.
- `badge` (string, default `New arrival`) — Badge shown on the product image; falsy hides it.
- `price` (string, default `$148`) — Current price, pre-formatted.
- `compare-at-price` (string, default `$185`) — Original price shown struck through; falsy hides it.
- `rating` (float, default `4.5`) — Average star rating value.
- `review-count` (int, default `312`) — Number of reviews shown next to the rating.
- `description` (string, default `A breathable engineered-knit upper over a responsive foam midsole — built for daily miles and easy enough to wear straight off the run.`) — Short product description shown under the rating.
- `sizes` (mixed|null, default `null`) — Size options for the option-group selector; null falls back to a default sample set.
- `selected-size` (string, default `9`) — Initially selected size value.
- `details-href` (string, default `#`) — Destination for the view-full-details link.
- `close-href` (string, default `#`) — Destination for the close button.
- `image-alt` (string, default `Aero Knit Runner shown from the side`) — Accessible label for the product image placeholder.
## Use when
- Opening a centered quick-view dialog for a single product with one square image, price, rating, a size selector, quantity stepper and an add-to-cart action.
- Use when the shopper needs a fast add-to-cart path from a single image, not a photo gallery or colour picker.
## Avoid when
- Needing an image gallery with a thumbnail strip and a colour swatch selector; use product-quick-view-gallery instead.
## Rules
- Render the installed block with `<x-blocks.product-quick-view-modal />` and pass data through its props; edit the copied file only for structural changes.
- Keep the semantic design tokens (`bg-background`, `text-muted-foreground`); never swap in raw colour utilities.
- Keep the `data-slot` attributes and the logical (start/end) spacing so the markup still mirrors under `dir="rtl"`.
## Links
- Docs: https://brokui.dev/blocks/product-quick-view-modal
- Registry JSON (files, props, contract): https://brokui.dev/r/open/blocks/product-quick-view-modal.json
Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.
Guidance
Use when
- Opening a centered quick-view dialog for a single product with one square image, price, rating, a size selector, quantity stepper and an add-to-cart action.
- Use when the shopper needs a fast add-to-cart path from a single image, not a photo gallery or colour picker.
Avoid when
- Needing an image gallery with a thumbnail strip and a colour swatch selector; use product-quick-view-gallery instead.
Anti-patterns
- Do not replace semantic props with conflicting utility classes.
- Do not remove labels, focus styles, or state attributes.
- Anatomy
Usage
Render the block as a component, passing data where useful:
<x-blocks.product-quick-view-modal />
Built from primitives
This block composes installed <brok:*> primitives and semantic design
tokens only — it does not reimplement any primitive. Re-theme it (light, dark, admin, customer) by
editing CSS variables; flip the preview to RTL to confirm it mirrors.
Source
The exact, editable file ui:add writes
into your app. The preview above renders this same source — there are no preview-only blocks.
@props([
'name' => 'Aero Knit Runner',
'brand' => 'Atlas Athletics',
'badge' => 'New arrival',
'price' => '$148',
'compareAtPrice' => '$185',
'rating' => 4.5,
'reviewCount' => 312,
'description' => 'A breathable engineered-knit upper over a responsive foam midsole — built for daily miles and easy enough to wear straight off the run.',
'sizes' => null,
'selectedSize' => '9',
'detailsHref' => '#',
'closeHref' => '#',
'imageAlt' => 'Aero Knit Runner shown from the side',
])
@php
$sizes ??= ['7', '8', '9', '10', '11', '12'];
@endphp
<section {{ $attributes->merge(['class' => 'flex min-h-svh items-center justify-center bg-muted/40 px-4 py-12 text-foreground']) }}>
<x-ui.card
role="dialog"
aria-modal="true"
aria-label="{{ __('Product quick view') }}"
class="relative w-full max-w-3xl overflow-hidden rounded-lg border border-border bg-card p-0 shadow-xl"
>
{{-- Close (top end) --}}
<x-ui.button
:href="$closeHref"
variant="ghost"
size="icon"
class="absolute end-3 top-3 z-10 size-9 rounded-full text-muted-foreground hover:text-foreground"
aria-label="{{ __('Close quick view') }}"
>
<svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M18 6 6 18" />
<path d="m6 6 12 12" />
</svg>
</x-ui.button>
<div class="grid grid-cols-1 gap-0 sm:grid-cols-2">
{{-- Image (left) --}}
<div class="relative aspect-square w-full overflow-hidden bg-muted">
@if ($badge)
<x-ui.badge class="absolute start-3 top-3 z-10 shadow-sm">{{ __($badge) }}</x-ui.badge>
@endif
<svg
class="size-full text-muted-foreground/40"
viewBox="0 0 200 200"
fill="none"
role="img"
aria-label="{{ __($imageAlt) }}"
>
<rect width="200" height="200" fill="currentColor" fill-opacity="0.08" />
<path
d="M28 132c14-6 22-18 30-30 6-9 11-16 21-16 7 0 11 5 18 9 6 3 13 4 22 4 14 0 24 7 33 16l20 21H28v-4Z"
fill="currentColor"
fill-opacity="0.55"
/>
<circle cx="70" cy="74" r="9" fill="currentColor" fill-opacity="0.5" />
</svg>
</div>
{{-- Details (right) --}}
<div class="flex flex-col gap-4 p-6 sm:p-8">
<div class="flex flex-col gap-2 pe-8">
@if ($brand)
<p class="text-sm font-semibold uppercase tracking-wide text-muted-foreground">{{ __($brand) }}</p>
@endif
<h2 class="text-pretty text-xl font-semibold leading-tight tracking-tight sm:text-2xl">{{ __($name) }}</h2>
</div>
<div class="flex items-center gap-4">
<span class="text-xl font-bold tracking-tight">{{ $price }}</span>
@if ($compareAtPrice)
<span class="text-base text-muted-foreground line-through">{{ $compareAtPrice }}</span>
@endif
</div>
<div class="flex items-center gap-2">
<x-ui.rating :value="$rating" size="sm" read-only />
<span class="text-sm text-muted-foreground">
{{ number_format((float) $rating, 1) }}
({{ trans_choice('{0}No reviews|{1}:count review|[2,*]:count reviews', $reviewCount, ['count' => number_format($reviewCount)]) }})
</span>
</div>
<p class="line-clamp-2 text-pretty text-sm leading-relaxed text-muted-foreground">
{{ __($description) }}
</p>
<x-ui.separator class="my-2" />
{{-- Size selector --}}
<div class="flex flex-col gap-2">
<span class="text-sm font-medium text-foreground" aria-hidden="true">{{ __('Size') }}</span>
<x-ui.option-group
name="size"
:options="$sizes"
:selected="$selectedSize"
size="sm"
:label="__('Size')"
/>
</div>
{{-- Quantity --}}
<div class="flex flex-col gap-2">
<span class="text-sm font-medium text-foreground" aria-hidden="true">{{ __('Quantity') }}</span>
<x-ui.number-field
variant="stepper"
size="md"
:value="1"
:min="1"
:max="10"
:label="__('Quantity')"
class="w-fit"
/>
</div>
<div class="mt-2 flex flex-col gap-4">
<x-ui.button type="button" size="lg" class="w-full">
<svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<circle cx="8" cy="21" r="1" />
<circle cx="19" cy="21" r="1" />
<path d="M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12" />
</svg>
{{ __('Add to cart') }}
</x-ui.button>
<a href="{{ $detailsHref }}" class="inline-flex items-center justify-center gap-2 text-sm font-medium text-link hover:underline">
{{ __('View full details') }}
<svg class="size-4 rtl:-scale-x-100" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M5 12h14" />
<path d="m12 5 7 7-7 7" />
</svg>
</a>
</div>
</div>
</div>
</x-ui.card>
</section>
Ownership & lifecycle
Owner, release state, review evidence and adoption for this item.
- Owner
- Platform UI (@JoshJML)
- Current version
-
1.1.2 - Status
- Stable
- License
-
open - Deprecation
- Not deprecated
- Contract
-
v1 - Foundation
-
≥ 1.0.0