PHPackages                             ganyicz/bond - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Templating &amp; Views](/categories/templating)
4. /
5. ganyicz/bond

ActiveLibrary[Templating &amp; Views](/categories/templating)

ganyicz/bond
============

Modern component authoring for Laravel Blade and Alpine.js

0.0.7(4mo ago)292333↓100%10[1 issues](https://github.com/ganyicz/bond/issues)MITJavaScript

Since Aug 17Pushed 4mo ago9 watchersCompare

[ Source](https://github.com/ganyicz/bond)[ Packagist](https://packagist.org/packages/ganyicz/bond)[ RSS](/packages/ganyicz-bond/feed)WikiDiscussions main Synced today

READMEChangelog (7)Dependencies (1)Versions (9)Used By (0)

[![Banner](https://raw.githubusercontent.com/ganyicz/bond/main/art/banner.png)](https://raw.githubusercontent.com/ganyicz/bond/main/art/banner.png)

> ⚠️ **Alpha release:**
> This package is currently under active development and not yet intended for production use; It is best to try on a fresh Laravel project. Feedback and contributions are welcome!

Bond brings modern component authoring to Laravel Blade and Alpine.js. It introduces a few features inspired by React and Vue, making it easier to write structured, maintainable components. Bond also ships with a VS Code extension that adds syntax highlighting, autocomplete, and error checking.

[Learn more about the project](https://github.com/ganyicz/bond/issues/3)

[Join the Discord server](https://discord.com/invite/wsF68edVdW)

Installation
------------

[](#installation)

Install Bond into your project using Composer:

```
composer require ganyicz/bond
```

Next, add the following lines to your `resources/js/app.js` file. Bond will compile all scripts extracted from your Blade files here.

```
import '../../vendor/ganyicz/bond/js/alpine';
import 'virtual:bond';
```

Finally, update your `vite.config.js` to register Bond:

```
import {
    defineConfig
} from 'vite';
import laravel from 'laravel-vite-plugin';
import tailwindcss from "@tailwindcss/vite";
+ import bond from './vendor/ganyicz/bond/dist/vite-plugin';

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            refresh: true,
        }),
        tailwindcss(),
+       bond(),
    ],
    server: {
        cors: true,
    },
});
```

If you're using Alpine.js CDN, make sure it's registered *after* your `app.js` file.

```

    @vite(['resources/css/app.css', 'resources/js/app.js'])

```

If you're using Livewire, you don't need to worry about this, as Livewire automatically loads Alpine.js for you. Just make sure your `app.js` file is registered somwhere in the `` tag.

VS Code Extension
-----------------

[](#vs-code-extension)

For the best development experience, install the [Bond VS Code extension](https://marketplace.visualstudio.com/items?itemName=ganyicz.bond-vscode-extension). It provides syntax highlighting, autocomplete, and error checking for both Bond components and Alpine.js attributes. The extension will be open-sourced in a future release.

Make sure to also install the official [Laravel extension](https://marketplace.visualstudio.com/items?itemName=laravel.vscode-laravel).

Bond will only load in files with language mode set to `Blade`.

Quick guide
-----------

[](#quick-guide)

Make sure you are familiar with both [Alpine.js](https://alpinejs.dev/start-here) and [Laravel Blade](https://laravel.com/docs/12.x/blade), as Bond builds on top of these technologies and supports all their features.

When ready, start your Vite development server:

```
npm run dev
```

### Creating a new component

[](#creating-a-new-component)

Bond is intended to be used within Blade components. Create one in `resources/views/components`. You can use the following Artisan command:

```
php artisan make:view components.alert
```

Then add a `` tag and `{{ $attributes }}` as described below.

### ``

[](#script-setup)

This is where you'll define props, state, and functions for this component. Bond’s Vite plugin will scan all Blade files within your `resources/views` directory, extract code from `` tags and bundle it into a single JavaScript file. The script tags will never actually be rendered on the page.

```

    mount((props: {
        //
    }) => ({
        //
    }))

```

Important

Since the code will get extracted into a JavaScript file, you cannot use Blade within the script tag.

The component gets automatically mounted on the element where you place your `{{ $attributes }}`. In the background, Bond just adds directives like `x-data` and `x-component` to your attributes to identify and initialize the component.

```

    ...

```

Important

Components using `` are isolated from the outer scope by design. To pass data in, use props or slots.

### Defining props

[](#defining-props)

Props let you pass reactive data from outside into your component. Define them in the callback parameter of the mount function with a type annotation:

```

    mount((props: {
        message: string,
    }) => ({
        init() {
            console.log(props.message)
        }
    }))

```

Props can be accessed inside the `mount` function and in the template using the `props.` prefix.

```

```

### Passing props

[](#passing-props)

Once defined, any Alpine or Livewire variable can be passed in as a prop using the `x-` prefix:

```

```

All props are two-way bound by default. The `message` inside the component will reactively update when the outer variable changes and vice versa. (This behavior might change in future releases.)

You can also pass static values like numbers, strings, or functions.

```

```

Caution

Prop names cannot conflict with Alpine.js directives. For example, you cannot use `on`, `model`, or `text`. For the full list of reserved names, see the list of directives in [Alpine.js docs](https://alpinejs.dev/start-here).

### Defining data

[](#defining-data)

To define data and functions on your component, use the object returned from the `mount` function callback. When referencing data within that object, you must use the `this` keyword. In the template, you can access data directly without any prefix.

```

    mount((props: {
        message: string,
    }) => ({
        uppercase: false,
        toggle() {
            this.uppercase = !this.uppercase
        },
        get formattedMessage() {
            return this.uppercase
                ? props.message.toUpperCase()
                : props.message
        },
    }))

    Toggle

```

### Using components

[](#using-components)

After you've defined your component, you can use it in your Blade templates like this:

```

```

While this is a simple example, you can use these patterns to build complex components with multiple props, two-way data binding, integrate with Livewire and more.

### Slots

[](#slots)

Bond components are isolated, which also applies to slots. Any content you pass into a slot will NOT have access to the parent scope by default.

Let's use the example from before, but instead of passing the message as a prop, we will use a slot.

```

```

The `errors` variable will not be accessible.

To make the slot behave as expected, wrap it in an element with an `x-slot` directive inside your component.

```

    {{ $slot }}

```

Important

Directives used on an element with `x-slot` will also use the outer scope, not just its children.

### Imports

[](#imports)

Since Bond compiles `` tags with Vite, you can use any import supported in a JavaScript/TypeScript file:

```

    // NPM module
    import { twMerge } from 'tailwind-merge'

    // Local file
    import { createTodo } from '@/todo'

    // Raw file content
    import check from '@resources/img/icons/check.svg?raw'

    // Types
    import type { TodoItem } from '@/types'

    mount(...)

```

The `@` alias points to `resources/js` by default. You can [customize the aliases](https://laravel.com/docs/12.x/vite#aliases) in your `vite.config.js` file, however this will not reflect in the VS Code extension at the moment and only the default alias will work in your IDE.

Make sure to always import types using the `import type` syntax to avoid issues.

### Else statement

[](#else-statement)

Alpine does not support else statements out of the box. Bond adds *partial* support for it. The limitation is that the template with the `x-else` directive must be inside the parent template.

```

    Your subscription is active

        Your subscription has expired

```

A simpler custom syntax for control statements is planned:

```

    Your subscription is active

    Your subscription has expired

```

### Icons

[](#icons)

Dynamic icons in Alpine usually require rendering all icons and toggling with `x-show`.

With Bond, you can import SVGs and render them dynamically with `x-html`:

```

    import check from '@resources/img/icons/check.svg?raw'
    import circle from '@resources/img/icons/circle.svg?raw'

    mount(() => ({
        icons: {check, circle}
    }))

```

This will likely be revisited in the next release with a more structured approach to icons.

### TypeScript

[](#typescript)

Bond uses TypeScript to provide a terse syntax for props and also to power the IDE features. However, it disables the `strict` mode by default. This means you are not forced to use types. You can write regular JavaScript without getting type errors, but still get autocomplete and type hints in your IDE.

Options for both enabling `strict` mode and fully opting out of TypeScript will be available in the future.

#### Adding types to properties

[](#adding-types-to-properties)

If a property is not initialized immediately, use the `as` keyword to define its type:

```

    mount(() => ({
        value: null as number | null,
    }))

```

Important

TypeScript syntax is only supported inside ``. Alpine expressions are not bundled, and using types in them will cause runtime errors.

Roadmap
-------

[](#roadmap)

Warning

The following features are planned but not yet implemented. Feedback and contributions are encouraged.

#### Attribute syntax

[](#attribute-syntax)

Bond will support a JSX-like syntax for attributes. This makes it easier to visually distinguish between HTML/Blade attributes and reactive bindings. This syntax will be optional.

```

 console.log($el.value)}
    disabled={value
```

The example above would be compiled to:

```

```

#### Control statement tags

[](#control-statement-tags)

Alpine requires wrapping conditional or loop logic in `` tags, which can be verbose. Bond will introduce a cleaner syntax that will also enable real `else` statements.

The syntax below was designed to be visually distinct from Blade directives and its HTML-like structure will be easy to compile into Alpine.js code.

```

    Your subscription is active

    Your subscription has expired

    ...

```

Compiled output:

```

    Your subscription is active

        Your subscription has expired

```

#### Interpolation

[](#interpolation)

Bond will add support for inline template interpolation. This lets you write expressions directly in HTML with curly braces, similar to Vue or React:

```

Hello, {name}
```

`{name}` will be replaced with the actual value at runtime.

#### Cross-file IntelliSense (VS Code)

[](#cross-file-intellisense-vs-code)

The Bond VS Code extension will provide autocomplete and type checking for props on the outside of the component, ensuring type safety across files.

#### Common error diagnostics (VS Code)

[](#common-error-diagnostics-vs-code)

The Bond VS Code extension will include diagnostics for common errors in Alpine.js attributes, such as a missing key in a `x-for` loop, one root element per `` tag, and more.

#### Blade enhancements

[](#blade-enhancements)

While Bond primarily augments Alpine.js, several Blade-specific enhancements would be beneficial to improve modularity and organization.

**Multiple components per file**

```

@export
This is (x-summary)
@export('title')
This is (x-summary.title)
@export('header')
This is (x-summary.header)
@endexport
```

**Imports and aliases**

```

@import('app::checkout.summary', 'summary')

        Summary

```

```

@import('app::checkout.summary')

    Summary

```

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance77

Regular maintenance activity

Popularity32

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity31

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~15 days

Total

7

Last Release

124d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/01cfffb593c2e79d752f1df4099b816cf93419a61d4d9ebcca66675bdae4e450?d=identicon)[ganyicz](/maintainers/ganyicz)

---

Top Contributors

[![ganyicz](https://avatars.githubusercontent.com/u/3823354?v=4)](https://github.com/ganyicz "ganyicz (108 commits)")

---

Tags

laravelbladealpinejs

### Embed Badge

![Health badge](/badges/ganyicz-bond/health.svg)

```
[![Health](https://phpackages.com/badges/ganyicz-bond/health.svg)](https://phpackages.com/packages/ganyicz-bond)
```

###  Alternatives

[robsontenorio/mary

Gorgeous UI components for Livewire powered by daisyUI and Tailwind

1.4k421.8k13](/packages/robsontenorio-mary)[victorybiz/laravel-simple-select

Laravel Simple Select inputs component for Blade and Livewire.

13720.8k](/packages/victorybiz-laravel-simple-select)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
