ironflow/halo-ui
Composer 安装命令:
composer require ironflow/halo-ui
包简介
Modern, composable Blade UI component library for Laravel — elegant as shadcn, native as Blade.
README 文档
README
Modern, composable Blade UI component library for Laravel
Elegant as shadcn/ui, native as Blade. Built with Tailwind CSS v4, Alpine.js, and Blade Icons.
Status • Installation • Components • Theming • Customization • Testing • Contributing
Status
v4 is a from-scratch rebuild, currently at an early, deliberately small stage. Earlier versions accumulated dead code and a documentation/reality gap (classes and templates that were never wired up, a theme system that didn't actually theme anything). Rather than carry that forward, v4 starts over with a strict rule: every component that exists is real, tested, and themed correctly — nothing is listed here until it ships.
Today that's 35 components (including 6 layout components). More are added incrementally; see CHANGELOG.md for what's shipped and docs/ for what's next.
Features
- Zero-config assets —
@haloStyles/@haloScriptsserve the package's own built CSS/JS (Alpine.js bundled in) with novendor:publish, no Vite config, no separate Alpine install - Anonymous Blade components — no PHP classes to maintain, just
@props()and a Blade file - Real runtime theming — colors, radius, and dark/light are CSS custom properties (
--halo-*) mapped into Tailwind v4 via@theme; switching themes changes an attribute, not a build step - Copy-and-own — works out of the box after
composer require;php artisan halo:installis an optional eject for full customization - Blade Icons integration — icons resolve through Blade Icons' native component API, not a hand-rolled resolver
- Accessible by default — ARIA attributes and keyboard behavior are part of a component's first version, not an afterthought
- Alpine.js for interactivity — registered as named
Alpine.data()/Alpine.store(), invoked directly in Blade
Installation
Requirements
- PHP 8.2+
- Laravel 11+ or 12+
Tailwind and Alpine.js are not separate requirements — HaloUI ships its own built CSS and JS (Alpine.js is bundled inside the JS build), so there's nothing extra to install for the fast path below.
Install via Composer
composer require ironflow/halo-ui
Fastest path: two tags in your layout
No vendor:publish, no Vite config, no separate Alpine.js install. @haloStyles/@haloScripts serve the package's own built assets directly:
<!DOCTYPE html> <html lang="en" data-theme="{{ config('halo.theme.default') }}"> <head> <meta charset="UTF-8"> @haloStyles </head> <body> {{ $slot }} @haloScripts </body> </html>
That's the whole setup. <x-halo::button>, <x-halo::input>, <x-halo::badge>, theme switching, focus traps, roving-focus menus — all working, with no build step of your own.
Integrated path: your own Vite/Tailwind pipeline
If your app already runs Tailwind v4 and Alpine.js and you want HaloUI's classes to be purgeable/tree-shakeable alongside your own, skip @haloStyles/@haloScripts and wire the package's sources into your own build instead:
/* resources/css/app.css */ @import "tailwindcss"; @import "../../vendor/ironflow/halo-ui/resources/css/theme.css"; @source "../../vendor/ironflow/halo-ui/resources/views";
// resources/js/app.js import Alpine from 'alpinejs'; import '../../vendor/ironflow/halo-ui/resources/js/init.js'; // registers haloModal, haloDropdown, etc. window.Alpine = Alpine; Alpine.start();
Set 'assets' => ['serve' => false] in config/halo.php (publish it first with php artisan vendor:publish --tag=halo-config) so @haloStyles/@haloScripts, if you still use them anywhere, point at your own published/bundled files instead of the package's asset routes.
Eject and customize (optional)
halo:install copies the package's own component files into your app, so you can edit them directly:
# Eject every component php artisan halo:install --all # Eject specific components php artisan halo:install button input # Overwrite files already ejected php artisan halo:install --all --force
Once ejected to resources/views/components/halo/, your local copy takes precedence — the package's own components still work for anything you didn't eject.
Quick Start
<x-halo::button variant="primary" icon="check"> Save changes </x-halo::button> <x-halo::input name="email" type="email" icon="mail" placeholder="you@example.com" /> <x-halo::badge variant="success">Active</x-halo::badge> <x-halo::icon name="user" size="lg" /> <x-halo::alert variant="danger" dismissible> Something went wrong — please try again. </x-halo::alert> {{-- Modal: opened by name, from anywhere --}} <x-halo::button @click="$dispatch('open-modal', 'confirm-delete')"> Delete account </x-halo::button> <x-halo::modal name="confirm-delete"> <x-halo::modal.header>Delete account?</x-halo::modal.header> <x-halo::modal.body>This can't be undone.</x-halo::modal.body> <x-halo::modal.footer> <x-halo::button variant="outline" @click="$dispatch('close-modal')">Cancel</x-halo::button> <x-halo::button variant="danger">Delete</x-halo::button> </x-halo::modal.footer> </x-halo::modal>
Components
Full props reference for each lives in docs/{component}.md; this is the map.
Typography
| Component | Notes |
|---|---|
| Heading | <h1>–<h6> via level, each with a matching default type scale; size overrides the look without changing the tag |
| Text | Body copy; as (p/span/div/blockquote), size, muted |
Form
| Component | Notes |
|---|---|
| Button | Variants primary/secondary/outline/ghost/danger; sizes sm/md/lg; icon, iconPosition, loading, disabled |
| Input | Sizes sm/md/lg; icon, iconPosition, invalid, error (message + aria-describedby), disabled, auto-generated id |
| Textarea | Same size/invalid/error/disabled pattern as Input, plus rows and resize |
| Label | Pairs with any field via for; required adds a decorative * |
| Checkbox | Native <input type="checkbox"> wrapped in a <label>; themed via accent-halo-primary |
| Radio | Same pattern as Checkbox; never derives its id from the shared group name |
| Select | options prop (value => label) or slot-authored <option> tags; invalid/error like Input |
| Switch | Native <input type="checkbox" role="switch"> styled as a track/thumb toggle |
| File Upload | Drag-and-drop over a real <input type="file">; removable file list, multiple, accept |
| Image Upload | Same drag-and-drop pattern, restricted to images, with live thumbnail previews |
Display
| Component | Notes |
|---|---|
| Icon | Resolves any icon in the halo Blade Icons set (resources/icons/halo/*.svg) by name; sizes xs–xl |
| Badge | Variants primary/secondary/success/danger/warning |
| Avatar | src image, initials fallback, or generic icon; status dot |
| Spinner | Standalone loading indicator; also used internally by Button's loading state |
| Progress | Determinate (value/max) or indeterminate progress bar |
| Divider | Horizontal (with optional centered label) or vertical |
Card (+ .header/.body/.footer) |
Variants default/bordered/elevated |
Table (+ .row/.head/.cell) |
Styled wrappers around native <table>/<tr>/<th>/<td>; <thead>/<tbody> stay plain HTML |
Feedback
| Component | Notes |
|---|---|
| Alert | Variants info/success/warning/danger, each with a matching default icon; dismissible |
Overlays (Alpine-powered)
| Component | Notes |
|---|---|
Modal (+ .header/.body/.footer) |
Opened/closed by name via $dispatch('open-modal', name) — no :open prop to sync; traps focus while open, returns it to the trigger on close |
Dropdown (+ .item) |
trigger named slot; arrow keys move between items, closes on escape/outside click/selecting an item, returns focus to the trigger |
| Popover | trigger named slot for arbitrary rich content; no menu semantics, focus returns to the trigger on close |
| Tooltip | trigger named slot; shown on hover/focus, aria-describedby wired automatically |
| Toast | One global queue rendered by a single <x-halo::toast />; push via $store.haloToast.push(message, variant) |
Navigation (Alpine-powered)
| Component | Notes |
|---|---|
Tabs (.list, .trigger, .panel) |
default active tab; arrow keys roam between triggers |
Accordion (+ .item) |
multiple allows more than one item open at once; each item tracked by an explicit name or an auto-generated one |
Breadcrumb (+ .item) |
href for links, current for the non-interactive last item |
Layouts
| Component | Notes |
|---|---|
| Layout: Base | A full <!DOCTYPE html>…</html> skeleton, @haloStyles/@haloScripts already wired in — the fastest way to get a page rendering |
| Layout: Container | Max-width, centered content wrapper; size sm–xl|full |
| Layout: App Shell | Sidebar + topbar dashboard layout; off-canvas drawer below lg, static above it |
| Layout: Auth | Centered layout for login/register pages, optional logo slot |
| Layout: Two Column | Content + secondary sidebar (docs nav, settings nav); sidebarPosition left|right |
| Layout: Page Header | Title + description + right-aligned actions slot |
Each component's props, variant maps, and rendered markup live directly in its .blade.php file under resources/views/components/halo/ — read the source, it's short by design.
See CHANGELOG.md for release history and docs/ for per-component prop references.
Theming
Colors, radius, and light/dark are CSS custom properties defined in resources/css/theme.css, scoped to a data-theme attribute, and mapped into real Tailwind utility classes (bg-halo-primary, rounded-halo, ...) via Tailwind v4's @theme directive. There is no build-time "active theme" setting — switching themes means changing an attribute.
Built-in themes
| Theme | data-theme |
Character |
|---|---|---|
| Halo | halo (default) |
Blue, neutral radius — the baseline |
| Aurora | aurora |
Violet/teal accent, larger radius |
| Eclipse | eclipse |
Dark background, same blue family as Halo |
| Ember | ember |
Light, warm orange accent, sharper corners |
| Nocturne | nocturne |
Dark, near-black background, emerald accent |
<html data-theme="eclipse">
Switching at runtime
resources/js/init.js registers an Alpine.store('haloTheme', ...) that persists the choice in localStorage and applies it to <html>:
<button @click="$store.haloTheme.set('aurora')">Aurora</button>
Render the correct theme on first paint (before Alpine boots) by reading the configured default server-side:
<html data-theme="{{ config('halo.theme.default') }}">
Adding a theme
Add a [data-theme="yourname"] block to resources/css/theme.css defining the same --halo-* variables as the existing themes, then add 'yourname' to config('halo.theme.available') and to the THEMES array in resources/js/init.js.
Customization
Component-level
Every component merges any extra classes you pass, with the last-wins conflict resolution in halo_merge_classes() — a class you pass always overrides the component's own default for the same Tailwind utility family (bg-*, text-*, p{x,y,...}-*, etc.):
<x-halo::button class="px-10"> Wider button </x-halo::button>
Defaults
config/halo.php sets each component's default variant/size:
'defaults' => [ 'button' => ['variant' => 'primary', 'size' => 'md'], ],
Helper functions
// CVA-style variant recipe: base classes + variant/size maps + defaults halo_variants($config, $props, $extraClass); // Merge class strings, deduping conflicting utilities (last wins) halo_merge_classes(...$classGroups); // Read a component's configured default prop halo_default('button', 'variant'); // 'primary' // Read a theme.* config value theme('radius'); // 'rounded-halo'
Testing
HaloUI uses Pest:
composer test
composer test-coverage
it('applies the default variant and size classes', function () { $html = renderComponent('button', ['slot' => 'Save']); expect($html) ->toHaveClass('bg-halo-primary') ->toHaveClass('px-4 py-2'); });
Every component has a render test in tests/Components/, including a regression test on Icon that guards against a real bug this rebuild fixed (an icon resolver that could recurse into itself).
Contributing
Contributions are welcome — see CONTRIBUTING.md.
git clone https://github.com/AureDulvresse/halo-ui.git cd halo-ui composer install npm install composer test vendor/bin/pint --test npm run build
License
HaloUI is open-sourced software licensed under the MIT license.
Credits
- Inspired by shadcn/ui
- Built with Tailwind CSS
- Powered by Alpine.js
- Icons by Blade Icons
HaloUI — Built with ❤️ by Aure Dulvresse
ironflow/halo-ui 适用场景与选型建议
ironflow/halo-ui 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 19 次下载、GitHub Stars 达 4, 最近一次更新时间为 2025 年 10 月 18 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「ui」 「components」 「laravel」 「blade」 「alpine」 「tailwind」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 ironflow/halo-ui 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 ironflow/halo-ui 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 ironflow/halo-ui 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Web Font Loader gives you added control when using linked fonts via @font-face.
Ariadne Component Library: xml writer and parser Component
Ariadne Component Library: Cache Component
Ariadne Component Library: hierarchical configuration management Component
Ariadne Component Library: user and group rights management Component
Ariadne Component Library: W3C style events Component
统计信息
- 总下载量: 19
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 5
- 点击次数: 26
- 依赖项目数: 1
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-10-18