Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ux Native Laravel Package

symfony/ux-native

Symfony UX Native lets you build native iOS and Android apps using Symfony, Twig, and Turbo, wrapping your server-rendered web UI in native shells. Reuse existing Symfony skills and components to deliver mobile experiences without a separate frontend stack.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony UX bundle, not a Laravel package. Before anything else, confirm whether you actually need it: symfony/ux-native is the Symfony-side integration for Hotwire Native (the 37signals hybrid mobile app framework), and its value is mostly in (a) detecting native requests, (b) generating the Hotwire Native path configuration JSON, and (c) providing Twig helpers/bridge markup. All three are thin enough to reimplement in a Laravel app in an afternoon.

Minimal steps if you still want to pull it in:

  1. composer require symfony/ux-native and immediately check composer.json for the required symfony/http-kernel, symfony/dependency-injection, and symfony/config version constraints — if they conflict with your Laravel/Symfony transitive deps, stop here and reimplement instead.
  2. There is no NativeServiceProvider; Symfony bundles register through config/bundles.php and the framework's kernel. In Laravel you must manually instantiate the runtime classes you need (native detector, path-config builder) inside a small NativeBridgeServiceProvider, or just copy the logic. Do not try to boot NativeBundle — it expects KernelInterface, the Symfony event dispatcher, and bundle config merging.
  3. Look first at NativeBundle.php (what it registers), the Native runtime class (the UA/context checks), the Twig extension (what helpers you'll need to port to Blade), and the path-configuration generator (the only genuinely non-trivial piece).
  4. First use case: a middleware that flags Hotwire Native / Turbo Native in the User-Agent as a request attribute, plus a GET /native/path-configuration.json route. That is the entire minimum viable integration — everything else is layout branching.

A realistic outcome for most Laravel teams: install it once to read the source, then delete it and write ~150 lines of your own code.

Implementation Patterns

Native detection middleware. Hotwire Native apps append a token to the webview UA (e.g. ... Safari ... Hotwire Native iOS; Turbo Native Android). Register a global middleware that checks the UA, sets $request->attributes->set('native', true), and optionally captures the platform (ios/android). Share the flag with views via a view composer so Blade can branch layouts.

Dual layout strategy. Keep one Blade layout per platform ("web" and "native"). The native layout strips your site chrome (header, footer, nav) because the native shell provides the navigation bar. This is the single biggest day-to-day behavior: @extends($native ? 'layouts.native' : 'layouts.app') or a @yield/component swap.

Path configuration endpoint. This is the core Hotwire Native contract. Serve JSON from a route and keep the patterns in config/native.php:

// config/native.php
return [
    'settings' => ['screenshots_enabled' => true],
    'rules' => [
        ['patterns' => ['/login$'], 'properties' => ['context' => 'modal']],
        ['patterns' => ['/checkout/.*'], 'properties' => ['context' => 'modal', 'pull_to_refresh_enabled' => false]],
        ['patterns' => ['/.*'], 'properties' => ['context' => 'default']],
    ],
];

Order matters — most specific first. Cache it (Cache-Control: public, max-age=3600) because the native app fetches it once per launch.

Turbo must actually work. ux-native assumes Turbo Drive/Frames/Streams are enabled on the web side. In Laravel that means @hotwired/turbo via Vite, data-turbo-frame attributes in Blade, and honoring Turbo-Frame request headers (Laravel returns the full page by default; you need to return frame-only partials). Without Turbo working, the Symfony package's helpers buy you nothing.

Native bridge components. Hotwire Native exposes bridge components (button, menu, form). The Symfony package likely renders them through Twig components; port the equivalent HTML (the data-* bridge attributes) into Blade components named x-native.button, x-native.menu. Keep these in one directory so upgrades are auditable.

Form and navigation flow. Always POST → redirect → GET. Native navigation treats a 200 HTML response to a form submission as a "replace" and can leave the back stack in a weird state. Flash messages work, but they must render inside the native layout or the user never sees them.

Auth and sessions. The webview shares cookies with the origin, so Laravel session auth works, but you must get the cookie domain right. Set SESSION_DOMAIN to the host the native app loads, use SameSite=Lax (not Strict), and make sure APP_URL matches scheme/host or asset and redirect URLs will point to the wrong place. For a Sanctum-flavored setup, add the native host to SANCTUM_STATEFUL_DOMAINS.

Testing. Add a feature test helper that sets the native UA ($this->withHeader('User-Agent', '... Hotwire Native iOS ...')) and assert on layout selection and the path-config JSON. Also add a "debug override" query string (?native=1) so QA can test in a desktop browser.

Gotchas and Tips

  • The bundle will not auto-register in Laravel. No service provider, no config publish, no facade. Symfony's NativeBundle requires KernelInterface, Bundle config merging, and the Symfony event dispatcher. Either bootstrap the handful of classes manually or treat the repo as a spec.
  • Twig vs Blade. Every helper the package ships (native_* functions, Twig components) has to be ported. Don't assume you can call them from Blade.
  • Type hints are mostly fine, config is not. Laravel's Illuminate\Http\Request extends Symfony\Component\HttpFoundation\Request, so runtime classes accepting the Symfony request will usually work. But anything resolving services from a container or reading bundle config (symfony/ux-native's Configuration.php) will throw — there is no native config tree in Laravel.
  • 12 stars, pre-1.0 semantics. Pin the exact version in composer.json and vendor-review the diff on every bump. The API surface (particularly attribute names on path-config rules and Twig helper signatures) is the most likely thing to churn.
  • UA detection is brittle. Hotwire Native appends to the platform webview UA, which differs between iOS (WKWebView) and Android (Chrome Custom Tabs). Match on the Hotwire Native/Turbo Native token, not the whole string, and always provide a ?native=1 escape hatch for debugging.
  • Path-config regex is not PCRE by default. Hotwire Native matches against the URL path; some versions use simple regex, and anchored $/^ behavior differs from PHP's preg_match. Test each rule against the actual URL the app requests (/orders/123, not the full origin).
  • context: modal vs default is the most common source of "double nav bar" and "back button does nothing" bug reports. When in doubt, leave default and add a native close button manually.
  • Asset URLs must be absolute. asset() and route() are fine, but if APP_URL is http://localhost in a staging build, the native shell will fail to load pages. Fail loudly at boot if APP_URL scheme isn't https outside local.
  • CSRF in the webview. Cookie-based CSRF works if the webview shares the origin, but SameSite=None; Secure is required if the native shell ever loads from a different host. Verify in the simulator, not just a browser.
  • Debugging. Tail the Laravel log for UA strings and /native/path-configuration.json hits; listen for turbo:before-fetch-request in the webview's remote inspector (Safari → Develop → Simulator, or chrome://inspect for Android). Log the resolved path-config rule per request during development.
  • Extension points to plan for. Wrap the path-config generator behind a PathConfiguration interface and the detection behind a single middleware. If you later drop the Symfony dependency, you swap two classes instead of chasing call sites.
  • Honest recommendation. For a Laravel codebase, use this package as a reference implementation, not a dependency. The reusable logic is small, the Symfony wiring is dead weight, and a native-detection middleware plus a JSON route is something you can own and test.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route