- Getting Started
- The Basics
- Concepts
- SuperNative
-
EDGE Components
- Introduction
- Activity Indicator
- Badge
- Bottom Navigation
- Bottom Sheet
- Button
- Button Group
- Canvas
- Carousel
- Checkbox
- Chip
- Column
- Divider
- Gesture Area
- Icon
- Icons
- Image
- Layout & Styling
- List
- Menus
- Modal
- Pressable
- Progress Bar
- Radio Group
- Row
- Scroll View
- Select
- Shapes
- Side Navigation
- Slider
- Spacer
- Stack
- Tab Row
- Text
- Text Input
- Toggle
- Top Bar
- Virtual List
- Web View
- Plugins
- Testing
- Architecture
You're viewing pre-release documentation — version 4.x is in beta
Features, APIs and behaviour may change before the stable release. View the stable version (3.x)
Introduction
What is EDGE?#
EDGE (Element Definition and Generation Engine) is NativePHP for Mobile's component system that transforms Blade template syntax into platform-native UI elements that look beautiful whichever device your users are using.

Instead of rendering in the web view, EDGE components are compiled into truly native elements and live apart from the web view's lifecycle. This means they are persistent and offer truly native performance.
There's no custom rendering engine and complex ahead-of-time compilation process, just a lightweight transformation step that happens at runtime. You end up with pure, fast and flexible native components — all configured by PHP!
Available Components#
EDGE provides a full suite of native UI components for building your app, from layout containers and typography to interactive forms and navigation chrome.
Layout#
- Layout & Styling - Shared sizing, spacing, flex, style, and event attributes available on all elements
- Column - Vertical flex container
- Row - Horizontal flex container
- Scroll View - Scrollable container with virtualization
- Stack - Overlay container (ZStack) for layering elements
- Spacer - Flexible space element
- Pressable - Touch-sensitive container wrapper
- Web View - Embed web content as a native element and surround it with native UI
Content#
- Text - Text display with font sizing, weight, color, and alignment
- Image - Image display with fit modes and tinting
- Icon - Platform-native icons (SF Symbols on iOS, Material Icons on Android)
- Divider - Horizontal line separator
- Activity Indicator - Loading spinner
- Progress Bar - Linear progress indicator
- Badge - Count or label pill marker
Forms#
- Button - Tappable button with variants, sizes, and disabled / loading state
- Button Group - Segmented single-choice selector
- Text Input - Outlined and filled text input variants
- Toggle - On/off switch control
- Checkbox - Tick/untick control with optional inline label
- Radio Group - Single-choice radio selector
- Select - Dropdown picker
- Slider - Continuous (or stepped) value selector
- Chip - Compact selectable tag
Navigation#
- Bottom Navigation - The always-accessible bottom navigation bar
- Top Bar - A title bar with action buttons
- Side Navigation - A slide-out navigation drawer
- Tab Row - Horizontal tab strip for in-screen sectioning
Lists & data#
- List - Virtualized list with pull-to-refresh, end-reached, and swipe actions
- List Item - Material3 row with leading + trailing slot system
- Carousel - Horizontal paging carousel
Overlays#
- Bottom Sheet - Modal bottom sheet for contextual actions and forms
- Modal - Full-screen modal overlay
Drawing#
How It Works#
<native:bottom-nav> <native:bottom-nav-item id="home" icon="home" label="Home" url="/home" /></native:bottom-nav>
You simply define your components in Blade and EDGE processes these during each request, passing instructions to the native side. The native UI rendering pipeline takes over to generate your defined components and builds the interface just the way your users would expect, enabling your app to use the latest and greatest parts of each platform, such as Liquid Glass on iOS.
Under the hood, the Blade components are compiled down to a simple JSON configuration which we pass to the native side. The native code already contains the generic components compiled-in. These are then rendered as needed based on the JSON configuration.
The native: prefix is optional#
<native:column> and <column> compile to exactly the same thing — the prefix is optional. We use it throughout
these docs for two reasons:
- Clarity —
<native:button>is unmistakably a native component, never confused with an HTML<button>. - IDE support — editors resolve the prefixed form to its component class and offer attribute autocomplete on
props; a bare
<column>reads as plain HTML, so you lose that typeahead.
Drop the prefix for terser templates whenever you prefer — both forms are fully supported.
Why Blade?#
Blade is an expressive and straightforward templating language that is very familiar to most Laravel users, and also super accessible to anyone who's used to writing HTML. All of our components are Blade components, which allows us to use Blade's battle-tested processing engine to rapidly compile the necessary transformation just in time.
Where to define your native components#
They can be defined in any Blade file, but for them to be processed, that Blade file will need to be rendered. We
recommend putting your components in a Blade component that is likely to be rendered on every request, such as your
main layout, e.g. layouts/app.blade.php or one of its child views/components.
Props Validation#
EDGE components enforce required props validation to prevent misconfiguration. If you're missing required props, you'll see a clear error message that tells you exactly what's missing and how to fix it.
For example, if you forget the label prop on a bottom navigation item:
EDGE Component <native:bottom-nav-item> is missing required properties: 'label'.Add these attributes to your component: label="..."
The error message will list all missing required props and show you exactly which attributes you need to add. This validation happens at render time, making it easy to catch configuration issues during development.
Each component's documentation page indicates which props are required vs optional.
Using Inertia?#
Each link in an EDGE component will do a full post back to PHP, which may not be what you want if you are using Inertia. To transform these requests into Inertia <Link>, add router to your window object:
import { router } from '@inertiajs/vue3'; declare global { interface Window { router: typeof router; }} window.router = router;
in no time