Action Response
The NativeBlade facade builds native actions and returns them from a Livewire component. Actions are chainable and flushed with ->toResponse().
How Bridges Work
There are two equivalent ways to invoke any built-in plugin:
1. From Blade (user-triggered)
<button wire:nb-bridge="action" wire:nb-payload='{"key":"value"}'>
Click me
</button>
Fires on tap without a Livewire round-trip. Best for pure UI actions.
2. From PHP (programmatic)
use NativeBlade\Facades\NativeBlade;
use NativeBlade\Plugins\Notification;
public function save()
{
// ... business logic
return NativeBlade::notification(function (Notification $n) {
$n->title('Saved!')->body('Your changes are safe.');
})->toResponse();
}
The facade returns a NativeResponse. From a Livewire component action you must call ->toResponse() on it to dispatch the native actions; returning it bare does not dispatch. (Inside a push or deep-link handler you return the bare NativeResponse instead, because the internal route calls ->toResponse() for you.) Every method is chainable, so you can queue multiple actions into one response and call ->toResponse() once at the end:
return NativeBlade::alert(fn (Dialog $d) => $d->title('Hey')->message('Welcome back!'))
->notification(fn (Notification $n) => $n->title('Heads up')->body('3 new lessons available'))
->navigate('/dashboard')
->transition('fade')
->toResponse();
Both paths end up in the same JavaScript dispatcher (js/wasm-app/bridge.js) and call the same native API. The difference is purely where the trigger comes from.
The NativeBlade Facade
The NativeBlade\Facades\NativeBlade facade is the primary PHP entry point for native actions, state, and platform detection.
Native action builders
Every action below is available both as a direct call on the facade and as a chained method on an existing response:
// Direct (starts a new response):
NativeBlade::vibrate(200);
// Chained (appends to an existing response):
return NativeBlade::notification(fn (Notification $n) => $n->title('Saved')->body('Changes persisted'))
->vibrate(200)
->toResponse();
| Category | Methods |
|---|---|
| Dialogs | alert(Closure), confirm(Closure) |
| Notifications | notification(Closure), scheduleNotification(Closure) |
| Clipboard | clipboardWrite($text), clipboardRead(?Closure) |
| Geolocation | geolocation(?Closure) |
| Haptics | vibrate($ms = 100), impact($style = 'medium'), selection() |
| Biometric | biometric(Closure) |
| Barcode | scan(?Closure) |
| NFC | nfcRead(?Closure) |
| Opener | openUrl($url), openFile($path) |
| OS | osInfo() |
| In-App Review | requestReview() |
| Secure Storage | setSecure($key, $value), getSecure($key, $id = null), forgetSecure($key) |
| Sharing | share($text = null, $url = null) |
| Analytics | analytics(Closure) |
| AdMob | requestAdConsent(array $testDeviceIds = []), rewardedAd(Closure), interstitialAd(Closure) |
| Payments | products(array $productIds), purchase(Closure), restorePurchases(), subscriptionStatus(array $productIds = []) |
| Camera | camera(?Closure), gallery(?Closure) |
| Navigation | navigate($path, $replace = false) |
| Modal | showModal(), hideModal() |
| Shell | shell(Closure) (desktop only) |
| Process | exit() |
All closure-based builders live in NativeBlade\Plugins\* (Dialog, Notification, Camera, Biometric, Scan, Geolocation, Clipboard, Nfc). Builders marked with ?Closure (nullable) let you omit the closure when you don’t need to configure anything, useful for the simple NativeBlade::geolocation() / NativeBlade::scan() case.
Modifiers (attach to the last action)
After any action, chain any of these to customize it:
| Modifier | Applies to |
|---|---|
transition($type) |
navigate, 'none' | 'slide' | 'fade' |
replace($bool = true) |
navigate |
All other per-action options live inside their dedicated
Plugins\*builder closures,Dialog,Notification,Camera,Biometric,Scan,Geolocation,Clipboard,Nfc. TheNativeResponseitself only keeps modifiers that affect the action queue (transition,replace).
Receiving Results in PHP
Bridges that return data post the result as a Livewire event. Listen with the #[On] attribute:
use Livewire\Attributes\On;
class MyComponent extends Component
{
#[On('nb:confirm-result')]
public function onConfirm($confirmed, $id = null) { /* ... */ }
#[On('nb:clipboard')]
public function onPaste($text, $id = null) { /* ... */ }
#[On('nb:geolocation')]
public function onLocation($position, $id = null) { /* ... */ }
#[On('nb:biometric')]
public function onBiometric($success, $error = null, $id = null) { /* ... */ }
#[On('nb:scan')]
public function onScan($result, $id = null) { /* ... */ }
#[On('nb:nfc')]
public function onNfcTag($tag, $id = null) { /* ... */ }
#[On('nb:os-info')]
public function onOsInfo($info) { /* ... */ }
#[On('nb:camera-result')]
public function onPhoto($data = null, $name = null, $mime = null, $size = null, $id = null) { /* ... */ }
#[On('nb:secure')]
public function onSecure($value = null, $id = null) { /* ... */ }
#[On('nb:shell-result')]
public function onShellResult($stdout = null, $stderr = null, $exitCode = null, $id = null) { /* ... */ }
}
Event names are always nb:<name>. They are automatically dispatched from the JS bridge via Livewire.dispatch() inside the iframe.
Every result-bearing bridge supports an optional $id argument as the last listener parameter. When a component has multiple calls to the same bridge (e.g. two cameras, three confirms, several geolocations), set ->id('unique_tag') inside the builder closure, or add "id":"unique_tag" to the Blade wire:nb-payload JSON, and the same tag comes back on the listener. Use match ($id) { ... } to route the response. When you only have one call per component, skip the id and the argument arrives as null.