Paywall
Conversion paywalls — inline plan upgrade, gated article content and a focused subscription card with billing toggle.
Preview
@props([
'articleHeading' => 'Why the best teams invest in async-first culture',
'articleCategory' => 'Culture',
'readTime' => '8 min read',
'overlayHeading' => 'Premium article',
'overlayCopy' => 'Subscribe to keep reading and unlock 500+ deep-dives.',
'signinUrl' => '#',
])
<x-ui.section space="xl" {{ $attributes }}>
<x-ui.container size="sm" gutter="sm">
{{-- Article meta --}}
<div class="mb-4 flex flex-wrap items-center gap-2">
<x-ui.badge variant="secondary">{{ __($articleCategory) }}</x-ui.badge>
<span class="text-sm text-muted-foreground">{{ __($readTime) }}</span>
</div>
{{-- Article heading --}}
<h1 class="mb-6 text-2xl font-bold tracking-tight sm:text-3xl">
{{ __($articleHeading) }}
</h1>
{{-- Fully-readable opening paragraphs --}}
<div class="prose-sm sm:prose space-y-4 text-muted-foreground">
<p>
{{ __('Asynchronous communication has become the cornerstone of high-performing distributed teams. When work transcends time zones and personal schedules, the ability to collaborate without real-time presence isn\'t just convenient — it\'s a competitive advantage.') }}
</p>
<p>
{{ __('Teams that master async patterns consistently report higher focus time, fewer interruptions, and more inclusive decision-making. Written artefacts replace ephemeral chat, creating a knowledge base that scales with the team rather than against it.') }}
</p>
</div>
{{-- Gated / locked content area --}}
<div class="relative mt-8 overflow-hidden">
{{-- Blurred dummy paragraphs (aria-hidden — decorative filler) --}}
<div aria-hidden="true" class="pointer-events-none select-none space-y-4 text-muted-foreground blur-sm">
<p class="text-sm leading-relaxed">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
</p>
<p class="text-sm leading-relaxed">
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt neque porro quisquam est qui dolorem ipsum.
</p>
<p class="text-sm leading-relaxed">
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident.
</p>
</div>
{{-- Gradient fade mask --}}
<div aria-hidden="true" class="absolute inset-0 bg-gradient-to-t from-background via-background/80 to-transparent"></div>
{{-- Lock overlay card --}}
<div class="absolute inset-x-0 bottom-0 flex flex-col items-center pb-2">
<div class="w-full max-w-sm rounded-lg border border-border bg-card p-6 text-center shadow-lg">
{{-- Lock badge --}}
<div class="mb-4 flex justify-center">
<x-ui.badge variant="outline" class="gap-2 px-4 py-2 text-sm">
<svg class="size-4 text-foreground" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<rect width="18" height="11" x="3" y="11" rx="2" ry="2"/>
<path d="M7 11V7a5 5 0 0110 0v4"/>
</svg>
{{ __('Members only') }}
</x-ui.badge>
</div>
<h2 class="mb-2 text-lg font-semibold tracking-tight text-foreground">
{{ __($overlayHeading) }}
</h2>
<p class="mb-6 text-sm text-muted-foreground">
{{ __($overlayCopy) }}
</p>
<x-ui.button class="w-full" size="md">
{{ __('Subscribe to read') }}
</x-ui.button>
<p class="mt-4 text-sm text-muted-foreground">
{{ __('Already a member?') }}
<a href="{{ $signinUrl }}" class="text-link underline underline-offset-2 hover:text-link/80 focus-visible:rounded-sm focus-visible:outline-2 focus-visible:outline-primary">
{{ __('Sign in') }}
</a>
</p>
</div>
</div>
</div>
{{-- Spacer so the overlay card has room to breathe --}}
<div class="h-64" aria-hidden="true"></div>
</x-ui.container>
</x-ui.section>
Installation
php artisan ui:add blocks/paywall-content
Registry contract
Install confidence
php artisan ui:add blocks/paywall-content
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.0.5
- License
- open
- Stability
- stable
- Contract
- v1
- Foundation
- ≥ 1.0.0
| Type | Generated target |
|---|---|
| blade | resources/views/blocks/paywall-content.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: Paywall Content (`paywall-content`)
Gated article paywall with readable opener paragraphs, blurred faux content behind a gradient mask, and a centered subscribe overlay card.
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/paywall-content
```
## Render it
```blade
<x-blocks.paywall-content />
```
## Props
- `article-heading` (string, default `Why the best teams invest in async-first culture`) — Article title shown above the gated content.
- `article-category` (string, default `Culture`) — Category badge shown above the article title.
- `read-time` (string, default `8 min read`) — Estimated read time shown beside the category badge.
- `overlay-heading` (string, default `Premium article`) — Heading shown inside the subscribe overlay card.
- `overlay-copy` (string, default `Subscribe to keep reading and unlock 500+ deep-dives.`) — Supporting copy shown inside the subscribe overlay card.
- `signin-url` (string, default `#`) — Destination for the already-a-member sign-in link.
## Use when
- Gating an in-progress article: showing readable opener paragraphs, then fading real or filler content behind a gradient mask.
- Overlaying a centered subscribe card with a lock badge on top of the blurred content, plus a sign-in link for existing members.
## Avoid when
- Prompting an upgrade with no specific gated content in view; use paywall-upgrade, or paywall-pricing for a billing-toggle plan card.
## Rules
- Render the installed block with `<x-blocks.paywall-content />` 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/paywall-content
- Registry JSON (files, props, contract): https://brokui.dev/r/open/blocks/paywall-content.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
- Gating an in-progress article: showing readable opener paragraphs, then fading real or filler content behind a gradient mask.
- Overlaying a centered subscribe card with a lock badge on top of the blurred content, plus a sign-in link for existing members.
Avoid when
- Prompting an upgrade with no specific gated content in view; use paywall-upgrade, or paywall-pricing for a billing-toggle plan card.
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.paywall-content />
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([
'articleHeading' => 'Why the best teams invest in async-first culture',
'articleCategory' => 'Culture',
'readTime' => '8 min read',
'overlayHeading' => 'Premium article',
'overlayCopy' => 'Subscribe to keep reading and unlock 500+ deep-dives.',
'signinUrl' => '#',
])
<x-ui.section space="xl" {{ $attributes }}>
<x-ui.container size="sm" gutter="sm">
{{-- Article meta --}}
<div class="mb-4 flex flex-wrap items-center gap-2">
<x-ui.badge variant="secondary">{{ __($articleCategory) }}</x-ui.badge>
<span class="text-sm text-muted-foreground">{{ __($readTime) }}</span>
</div>
{{-- Article heading --}}
<h1 class="mb-6 text-2xl font-bold tracking-tight sm:text-3xl">
{{ __($articleHeading) }}
</h1>
{{-- Fully-readable opening paragraphs --}}
<div class="prose-sm sm:prose space-y-4 text-muted-foreground">
<p>
{{ __('Asynchronous communication has become the cornerstone of high-performing distributed teams. When work transcends time zones and personal schedules, the ability to collaborate without real-time presence isn\'t just convenient — it\'s a competitive advantage.') }}
</p>
<p>
{{ __('Teams that master async patterns consistently report higher focus time, fewer interruptions, and more inclusive decision-making. Written artefacts replace ephemeral chat, creating a knowledge base that scales with the team rather than against it.') }}
</p>
</div>
{{-- Gated / locked content area --}}
<div class="relative mt-8 overflow-hidden">
{{-- Blurred dummy paragraphs (aria-hidden — decorative filler) --}}
<div aria-hidden="true" class="pointer-events-none select-none space-y-4 text-muted-foreground blur-sm">
<p class="text-sm leading-relaxed">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
</p>
<p class="text-sm leading-relaxed">
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt neque porro quisquam est qui dolorem ipsum.
</p>
<p class="text-sm leading-relaxed">
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident.
</p>
</div>
{{-- Gradient fade mask --}}
<div aria-hidden="true" class="absolute inset-0 bg-gradient-to-t from-background via-background/80 to-transparent"></div>
{{-- Lock overlay card --}}
<div class="absolute inset-x-0 bottom-0 flex flex-col items-center pb-2">
<div class="w-full max-w-sm rounded-lg border border-border bg-card p-6 text-center shadow-lg">
{{-- Lock badge --}}
<div class="mb-4 flex justify-center">
<x-ui.badge variant="outline" class="gap-2 px-4 py-2 text-sm">
<svg class="size-4 text-foreground" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<rect width="18" height="11" x="3" y="11" rx="2" ry="2"/>
<path d="M7 11V7a5 5 0 0110 0v4"/>
</svg>
{{ __('Members only') }}
</x-ui.badge>
</div>
<h2 class="mb-2 text-lg font-semibold tracking-tight text-foreground">
{{ __($overlayHeading) }}
</h2>
<p class="mb-6 text-sm text-muted-foreground">
{{ __($overlayCopy) }}
</p>
<x-ui.button class="w-full" size="md">
{{ __('Subscribe to read') }}
</x-ui.button>
<p class="mt-4 text-sm text-muted-foreground">
{{ __('Already a member?') }}
<a href="{{ $signinUrl }}" class="text-link underline underline-offset-2 hover:text-link/80 focus-visible:rounded-sm focus-visible:outline-2 focus-visible:outline-primary">
{{ __('Sign in') }}
</a>
</p>
</div>
</div>
</div>
{{-- Spacer so the overlay card has room to breathe --}}
<div class="h-64" aria-hidden="true"></div>
</x-ui.container>
</x-ui.section>
Ownership & lifecycle
Owner, release state, review evidence and adoption for this item.
- Owner
- Platform UI (@JoshJML)
- Current version
-
1.0.5 - Status
- Stable
- License
-
open - Deprecation
- Not deprecated
- Contract
-
v1 - Foundation
-
≥ 1.0.0