knppy/ui

Knppy UI is a robust Shadcn/ui port for Laravel applications.
946
Install
composer require knppy/ui
Latest Version:0.6.0
PHP:^8.3
License:MIT
Last Updated:Oct 10, 2026
Links: GitHub  ·  Packagist
Maintainer: michaelbeers

Knppy UI is a robust Shadcn/ui port for Laravel applications. Components are Blade views plus small Alpine modules that are copied into your project, so you own and can edit the code.

Requirements

  • PHP 8.3+ and Laravel 12 or 13
  • Tailwind CSS v4 and Vite (the components are styled with Tailwind classes)
  • Node and npm (Alpine.js and its plugins are installed through npm)

Installation

You can install the package via Composer:

composer require knppy/ui

Optionally publish the configuration file:

php artisan vendor:publish --tag="ui-config"

Usage

php artisan ui:install
php artisan ui:add button card dialog

Then use them as anonymous Blade components:

<x-ui.card>
    <x-ui.card-header>
        <x-ui.card-title>Team</x-ui.card-title>
    </x-ui.card-header>
    <x-ui.card-content>
        <x-ui.button variant="outline">Invite</x-ui.button>
    </x-ui.card-content>
</x-ui.card>

Families use flat kebab-case names (dialog, dialog-trigger, dialog-content, ...), not dotted ones. Pass extra classes with class; they are merged with the component defaults through tailwind-merge.

Setup

ui:install asks for a base color (currently only neutral; or pass --baseColor=neutral) and writes two files:

  • components.json, which holds the aliases paths and any extra registries. It refuses to run when the file already exists unless you pass --force.
  • resources/css/app.css, the Tailwind v4 entry with the theme variables (light and dark). It is overwritten, so back up an existing file first.

Make sure app.css is compiled by Vite. Dark mode is class based (.dark).

Adding Components

php artisan ui:add button
php artisan ui:add @knppy/button @acme/card --overwrite

Run ui:add without names to search the default registry and pick components interactively, or pass --all to add every component of the default registry.

To see what a registry offers, run ui:list (optionally with a registry such as @acme; the default registry is used otherwise):

php artisan ui:list
php artisan ui:list @acme

Listing reads registry.json next to the items (the URL template with {name} replaced by registry, or registry.json in a local directory); a registry must publish it to be listable. The bundled registry/r/registry.json is generated by composer registry:build.

Files are written to the aliases paths in components.json (aliases.ui for registry:ui files, aliases.js for registry:js files, aliases.components otherwise). Existing files are skipped unless --overwrite is given. Registry dependencies are installed too; missing Composer and npm packages are installed automatically (composer require / npm install in the project root; npm only when a package.json exists). Pass --skip-packages to print the commands instead.

A bare name uses default_registry; @namespace/name picks a registry. Registries are configured in config/ui.php and can be extended per project in components.json:

{
  "registries": {
    "@acme": "https://acme.test/r/{name}.json"
  }
}

A registry value is a URL template containing {name} or a local directory of {name}.json files. Each item is JSON with inline file content (shadcn style). If the remote @knppy registry is unavailable, the registry bundled with this package is used instead silently (pass -v to ui:add to see a notice; disable with UI_REGISTRY_FALLBACK=false); other registries never fall back.

Alpine.js components

Components that need Alpine ship a small JS module (resources/js/ui/dialog.js) and depend on the alpine item, which installs the loader resources/js/ui.js and alpinejs. Import the loader once in your app.js:

import './ui.js';

The loader uses Vite's import.meta.glob('./ui/*.js'), so every module ui:add drops into resources/js/ui/ registers itself with Alpine automatically. Delete a module and it stops being registered. The loader also adds x-data to <body> (unless it already has one) so magics like $toast work anywhere on the page. Add "js": "resources/js" to aliases in components.json if it is missing.

Livewire

When Livewire is on the page, its bundled Alpine instance is used and the loader does not start a second one. Components that expose state through x-modelable (for example dialog, select, checkbox, switch, slider, tabs) accept x-model and wire:model.

Helpers

Ui::classes('base')->add('more') builds class strings, and $attributes->twMerge('base classes') merges a component attribute bag with Tailwind-aware conflict resolution. Tune the merger (class groups, prefix, theme) under twMerge in config/ui.php.

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Thank you for considering contributing to Knppy UI! Please review our contributing guide to get started.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

Knppy UI is open-sourced software licensed under the MIT license.

Related Packages

anousss007/blatui

Open-source shadcn/ui for the BLAT stack (Blade, Laravel, Alpine.js, Tailwind CS...

12,070 260
electrik/slate

A shadcn-inspired Blade UI kit for Laravel with anonymous components, Tailwind C...

2,718 32
sparrowhawk-labs/pinion-ui

Blade UI component system for Laravel — daisyUI semantic colors, Alpine.js inter...

610 41

Version History

Version Released PHP Laravel License
0.6.0 ^8.3 ^12.0||^13.0 MIT
0.5.2 ^8.4 ^12.0||^13.0 MIT
0.5.1 ^8.4 ^12.0||^13.0 MIT
0.5.0 ^8.3 ^12.0||^13.0 MIT