blade-islands
v0.1.1
Published
Blade islands for Laravel
Maintainers
Readme
🏝️ Blade Islands For Laravel
Client-side island runtime for Blade.
Blade Islands lets you render small React, Vue, or Svelte components inside Laravel Blade views without turning your application into a full single-page app.
This package provides the browser runtime. The Blade directives that render island placeholders live in the companion Laravel package eznix86/blade-islands.
Contents
- Why Blade Islands?
- Installation
- Quick Start
- How It Works
- Entry Points
- Vite Setup
- Component Resolution
- Custom Root
- Preserve Mounted Islands
- Options
- Requirements
- Companion Package
- Blade Islands vs X
- Testing
- Contributing
- License
Why Blade Islands?
Blade Islands works well when your application is mostly server-rendered but still needs interactive UI in places such as:
- search inputs
- dashboards
- maps
- counters
- filters
- dialogs
Instead of building entire pages in a frontend framework, you can keep Blade as your primary rendering layer and hydrate only the parts of the page that need JavaScript.
Installation
Install Blade Islands, your frontend framework, and the matching Vite plugin.
React
npm install blade-islands react react-dom @vitejs/plugin-reactVue
npm install blade-islands vue @vitejs/plugin-vueSvelte
npm install blade-islands svelte @sveltejs/vite-plugin-svelteQuick Start
Add the runtime to resources/js/app.js, load that entry from your Blade layout, and render an island from Blade.
React
resources/js/app.js
import islands from 'blade-islands/react'
islands()Blade layout:
<head>
@viteReactRefresh
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>@react('ProfileCard', ['user' => $user])Resolves to resources/js/islands/ProfileCard.jsx.
Vue
resources/js/app.js
import islands from 'blade-islands/vue'
islands()Blade layout:
<head>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>@vue('ProfileCard', ['user' => $user])Resolves to resources/js/islands/ProfileCard.vue.
Svelte
resources/js/app.js
import islands from 'blade-islands/svelte'
islands()Blade layout:
<head>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>@svelte('ProfileCard', ['user' => $user])Resolves to resources/js/islands/ProfileCard.svelte.
How It Works
Blade Islands has two parts:
- the Laravel package renders island placeholders from Blade
- this package scans the DOM and mounts the matching frontend component
For example:
@react('Account/UsageChart', ['stats' => $stats])mounts:
resources/js/islands/Account/UsageChart.jsxEntry Points
Blade Islands provides framework-specific entry points:
import islands from 'blade-islands/react'
import islands from 'blade-islands/vue'
import islands from 'blade-islands/svelte'Each entry point mounts only its own island type.
Vite Setup
Register the plugin for the framework you use.
React
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
})If your Laravel layout loads a React entrypoint in development, include:
@viteReactRefreshVue
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
})Svelte
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
export default defineConfig({
plugins: [svelte()],
})Component Resolution
By default, Blade Islands looks for components in resources/js/islands.
Nested folders work automatically. For example:
@react('Billing/Invoices/Table', [...])
@vue('Billing/Invoices/Table', [...])
@svelte('Billing/Invoices/Table', [...])These resolve to:
resources/js/islands/Billing/Invoices/Table.jsx
resources/js/islands/Billing/Invoices/Table.vue
resources/js/islands/Billing/Invoices/Table.svelteCustom Root
If your components live outside the default root, pass both root and components:
import islands from 'blade-islands/vue'
islands({
root: '/resources/js/widgets',
components: import.meta.glob('/resources/js/widgets/**/*.vue'),
})Then:
@vue('Dashboard', [...])resolves to resources/js/widgets/Dashboard.vue.
Preserve Mounted Islands
Use preserve: true when the same DOM is processed more than once and you want Blade Islands to keep an existing island mounted instead of mounting it again.
This is useful when the page or a DOM fragment is recalculated and your frontend boot logic runs again.
@react('Dashboard/RevenueChart', ['stats' => $stats], preserve: true)
@vue('Dashboard/RevenueChart', ['stats' => $stats], preserve: true)
@svelte('Dashboard/RevenueChart', ['stats' => $stats], preserve: true)If you reuse a preserved component in a loop, give each island a unique key on the Blade side so the runtime can distinguish them correctly:
@foreach ($products as $product)
@react('Product/Card', ['product' => $product], preserve: true, key: "product-{$product->id}")
@endforeachOptions
Each entry point exports a default islands() function:
islands({
root: '/resources/js/islands',
components: import.meta.glob('/resources/js/islands/**/*.{jsx,tsx}'),
})root- component root used to derive names such asBilling/Invoices/Tablecomponents- Viteimport.meta.glob(...)map for the current framework
Requirements
- Vite
- React 18+ for
blade-islands/react - Vue 3+ for
blade-islands/vue - Svelte 5+ for
blade-islands/svelte
Companion Package
This runtime expects Blade placeholders generated by the Laravel package:
- Composer package:
eznix86/blade-islands - Repository:
laravel-blade-islands
Blade Islands vs X
Inertia.js
Inertia is a better fit when your application wants React, Vue, or Svelte to render full pages with a JavaScript-first page architecture.
Blade Islands is a better fit when your application is already Blade-first and you want to keep server-rendered pages while hydrating only selected components.
MingleJS
MingleJS is often used in Laravel applications that embed React or Vue components, especially in Livewire-heavy codebases.
Blade Islands is more naturally suited to Blade-first applications that want progressive enhancement with minimal architectural change. It does not depend on Livewire, and it may also be used alongside Livewire when that fits your application.
Laravel UI
Laravel UI is a legacy scaffolding package for frontend presets and authentication views.
Blade Islands solves a different problem: adding targeted client-side interactivity to server-rendered Blade pages.
Testing
npm install
npm testContributing
Contributions are welcome.
- Fork the repository
- Create a focused branch
- Add or update tests
- Run
npm test - Open a pull request with a clear summary
License
MIT
