Skip to main content
NativePHP Mobile provides Blade components that render as native UI elements on mobile devices. These components give your app a truly native feel with platform-specific navigation, buttons, and other UI elements.

Overview

Native Blade components are registered automatically by the NativeServiceProvider (NativeServiceProvider.php:330-372). They extend the EdgeComponent base class and communicate with native code through the Edge system.

How It Works

  1. Component Registration: Components are auto-discovered from src/Edge/Components/ and registered with Blade
  2. Rendering: When rendered, components are converted to native props and queued
  3. Middleware: The RenderEdgeComponents middleware sends queued components to native code after each request
  4. Native Rendering: The mobile app renders native UI elements based on the component data

Platform Detection Directives

Use these Blade directives to conditionally render content based on the platform:

@mobile / @web

Show different content for mobile vs web:
@mobile
    <x-native-top-bar title="Dashboard" />
    <div class="mobile-layout">
        <!-- Mobile-optimized content -->
    </div>
@endmobile

@web
    <nav class="desktop-nav">
        <!-- Desktop navigation -->
    </nav>
@endweb

@ios / @android

Platform-specific rendering:
@ios
    <!-- iOS-specific UI -->
    <div class="ios-style-header">Welcome</div>
@endios

@android
    <!-- Android-specific UI -->
    <div class="material-header">Welcome</div>
@endandroid
Use these directives to follow platform-specific design guidelines (Human Interface Guidelines for iOS, Material Design for Android).

Top Bar

Renders a native top app bar with title, subtitle, and actions.
<x-native-top-bar 
    title="Dashboard" 
    subtitle="Welcome back"
/>
Props:
title
string
Main title text
subtitle
string
Subtitle text (below title)
show-navigation-icon
bool
default:"true"
Show back/menu navigation icon
background-color
string
Background color (hex or named color)
text-color
string
Text color (hex or named color)
elevation
int
Shadow elevation (Android Material Design)

Top Bar Action

Adds action buttons to the top bar (must be child of <x-native-top-bar>).
<x-native-top-bar-action
    id="refresh"
    icon="refresh"
    label="Refresh"
    url="{{ route('dashboard.refresh') }}"
/>
Props (all required):
id
string
required
Unique identifier for this action
icon
string
required
Material icon name or SF Symbol name
label
string
required
Accessibility label
url
string
required
URL to navigate to when tapped
event
string
Optional event name to dispatch instead of navigation

Bottom Navigation

Renders a bottom navigation bar (Material/iOS style).
<x-native-bottom-nav 
    label-visibility="labeled"
    active-color="#1976D2"
>
    <x-native-bottom-nav-item
        id="home"
        icon="home"
        url="/dashboard"
        label="Home"
        :active="request()->is('dashboard')"
    />
    <x-native-bottom-nav-item
        id="search"
        icon="search"
        url="/search"
        label="Search"
    />
    <x-native-bottom-nav-item
        id="notifications"
        icon="notifications"
        url="/notifications"
        label="Notifications"
        badge="3"
        badge-color="#F44336"
    />
    <x-native-bottom-nav-item
        id="profile"
        icon="person"
        url="/profile"
        label="Profile"
        :news="true"
    />
</x-native-bottom-nav>
Bottom Nav Props:
label-visibility
string
default:"labeled"
How to show labels: labeled, selected, or unlabeled
active-color
string
Color for active item
dark
bool
Use dark theme variant
Bottom Nav Item Props:
id
string
required
Unique identifier
icon
string
required
Icon name
url
string
required
Navigation URL
label
string
required
Label text
active
bool
default:"false"
Whether this item is currently active
badge
string
Badge text (e.g., notification count)
badge-color
string
Badge background color
news
bool
default:"false"
Show “new” indicator dot

Side Navigation

Drawer-style side navigation panel.
<x-native-side-nav 
    label-visibility="labeled"
    :gestures-enabled="true"
>
    <x-native-side-nav-header
        title="My App"
        subtitle="v1.0.0"
        image-url="/images/logo.png"
    />
    
    <x-native-side-nav-group label="Main">
        <x-native-side-nav-item
            id="dashboard"
            icon="dashboard"
            label="Dashboard"
            url="/dashboard"
            :active="true"
        />
        <x-native-side-nav-item
            id="reports"
            icon="assessment"
            label="Reports"
            url="/reports"
        />
    </x-native-side-nav-group>
    
    <x-native-horizontal-divider />
    
    <x-native-side-nav-group label="Settings">
        <x-native-side-nav-item
            id="preferences"
            icon="settings"
            label="Preferences"
            url="/settings"
        />
    </x-native-side-nav-group>
</x-native-side-nav>
Props:
label-visibility
string
default:"labeled"
Label visibility mode
gestures-enabled
bool
default:"false"
Allow swipe gesture to open drawer
dark
bool
Use dark theme

Floating Action Button (FAB)

A prominent circular action button, typically used for primary actions.
<x-native-fab
    icon="add"
    label="Create"
    url="/create"
    size="regular"
    position="end"
    :bottom-offset="16"
    container-color="#1976D2"
    content-color="#FFFFFF"
/>
Props:
icon
string
required
Icon name
label
string
Optional label text (creates extended FAB)
url
string
Navigation URL
event
string
Event to dispatch instead of navigation
size
string
default:"regular"
Size: small, regular, or large
position
string
default:"end"
Position: start, center, or end
bottom-offset
int
Offset from bottom in dp/pt
elevation
int
Shadow elevation
corner-radius
int
Corner radius in dp/pt
container-color
string
Background color
content-color
string
Icon/text color

Creating Custom Components

You can create your own native components by extending EdgeComponent:
namespace App\Components;

use Native\Mobile\Edge\Components\EdgeComponent;

class CustomButton extends EdgeComponent
{
    protected string $type = 'custom_button';
    protected bool $hasChildren = false;
    
    public function __construct(
        public string $label,
        public ?string $url = null,
        public ?string $color = null,
    ) {}
    
    protected function requiredProps(): array
    {
        return ['label'];
    }
    
    protected function toNativeProps(): array
    {
        return [
            'label' => $this->label,
            'url' => $this->url,
            'color' => $this->color,
        ];
    }
}
Register it in a service provider:
Blade::component('custom-button', \App\Components\CustomButton::class);
Use it in Blade:
<x-custom-button 
    label="Click Me" 
    url="/action" 
    color="#FF5722" 
/>
To handle your custom component on the native side, you’ll need to implement the corresponding native code in Swift (iOS) and Kotlin (Android).

Component Lifecycle

Without Children

Components without children (like <x-native-fab>) are immediately added to the Edge queue:
// EdgeComponent::render()
Edge::add($this->type, $this->toNativeProps());

With Children

Components with children (like <x-native-bottom-nav>) use a context system:
// EdgeComponent::render()
$contextIndex = Edge::startContext();

// ... children are rendered ...

// View ends the context
Edge::endContext($contextIndex, $this->type, $this->toNativeProps());
This ensures children are properly nested in the component tree.

Edge System

The Edge system manages the component queue and sends it to native code:
use Native\Mobile\Edge\Edge;

// Add a component
Edge::add('button', ['label' => 'Click me']);

// Get all queued components
$components = Edge::all();

// Send to native layer (called by middleware)
Edge::set();

// Clear native UI
Edge::clear();

// Reset queue
Edge::reset();
You typically don’t need to call Edge methods directly - the middleware handles this automatically.

Complete Example

Here’s a complete page using multiple native components:
@extends('layouts.app')

@section('content')
    @mobile
        <x-native-top-bar 
            title="Dashboard"
            background-color="#1976D2"
            text-color="#FFFFFF"
        >
            <x-native-top-bar-action
                id="search"
                icon="search"
                label="Search"
                url="{{ route('search') }}"
            />
        </x-native-top-bar>

        <div class="content">
            <h1>Welcome to Dashboard</h1>
            <!-- Your content here -->
        </div>

        <x-native-bottom-nav active-color="#1976D2">
            <x-native-bottom-nav-item
                id="home"
                icon="home"
                url="/dashboard"
                label="Home"
                :active="true"
            />
            <x-native-bottom-nav-item
                id="explore"
                icon="explore"
                url="/explore"
                label="Explore"
            />
            <x-native-bottom-nav-item
                id="notifications"
                icon="notifications"
                url="/notifications"
                label="Alerts"
                badge="{{ $notificationCount }}"
            />
            <x-native-bottom-nav-item
                id="profile"
                icon="person"
                url="/profile"
                label="Profile"
            />
        </x-native-bottom-nav>

        <x-native-fab
            icon="add"
            url="{{ route('create') }}"
            container-color="#FF5722"
        />
    @endmobile

    @web
        <!-- Desktop layout -->
        <nav>...</nav>
        <div class="desktop-content">
            <h1>Welcome to Dashboard</h1>
            <!-- Your content here -->
        </div>
    @endweb
@endsection

Best Practices

Keep it simple: Native components have limited styling options. For complex layouts, use regular HTML/CSS in the WebView and native components only for navigation.
Platform consistency: Use @ios and @android directives to follow platform-specific design patterns. iOS users expect iOS patterns, Android users expect Material Design.
Performance: Native components are sent after each request. If you have many components updating frequently, consider reducing the number of native elements or batching updates.

Troubleshooting

Components Not Rendering

Make sure the RenderEdgeComponents middleware is registered (it’s added automatically by NativeServiceProvider):
// Check in app/Http/Kernel.php
protected $middleware = [
    // ...
    \Native\Mobile\Http\Middleware\RenderEdgeComponents::class,
];

Missing Required Props

If you see “Missing required props” errors, ensure all required props are provided:
<!-- ❌ Error: missing 'label' -->
<x-native-bottom-nav-item
    id="home"
    icon="home"
    url="/dashboard"
/>

<!-- ✅ Correct -->
<x-native-bottom-nav-item
    id="home"
    icon="home"
    url="/dashboard"
    label="Home"
/>

Next Steps

Architecture

Learn how Edge components work under the hood

Native APIs

Explore device APIs

Styling

Style your app

Examples

See complete examples

Build docs developers (and LLMs) love