schaefersoft/laravel-headless-ui
Installation:
composer require schaefersoft/laravel-headless-ui
No manual registration needed—auto-discovery handles it.
Import Assets: Add to your CSS:
@import '../../vendor/schaefersoft/laravel-headless-ui/resources/css/hui.css';
Add to your JS (pre-built):
import '../../vendor/schaefersoft/laravel-headless-ui/dist/js/hui.js';
First Use Case:
Use the x-hui::tabs component in a Blade view:
<x-hui::tabs>
<x-hui::tabs.tablist>
<x-hui::tabs.tab>Tab 1</x-hui::tabs.tab>
<x-hui::tabs.tab>Tab 2</x-hui::tabs.tab>
</x-hui::tabs.tablist>
<x-hui::tabs.panel>Content 1</x-hui::tabs.panel>
<x-hui::tabs.panel>Content 2</x-hui::tabs.panel>
</x-hui::tabs>
tabs.md, range-slider.md).x-hui:: prefix (e.g., x-hui::dropdown, x-hui::dialog).Component Composition:
tablist and tab inside tabs, followed by panel in order.
<x-hui::tabs :initial-index="1">
<x-hui::tabs.tablist class="flex gap-4">
<x-hui::tabs.tab>Settings</x-hui::tabs.tab>
<x-hui::tabs.tab>Profile</x-hui::tabs.tab>
</x-hui::tabs.tablist>
<x-hui::tabs.panel>Settings content</x-hui::tabs.panel>
<x-hui::tabs.panel>Profile content</x-hui::tabs.panel>
</x-hui::tabs>
track, thumb, and track.value for dual-thumb sliders.
<x-hui::range-slider>
<x-hui::range-slider.track>
<x-hui::range-slider.track.value/>
<x-hui::range-slider.thumb role="min" min="0" max="100" value="20"/>
<x-hui::range-slider.thumb role="max" min="0" max="100" value="80"/>
</x-hui::range-slider.track>
</x-hui::range-slider>
Dynamic Initialization:
:initial-index for tabs or data-active for one-off active states.value directly on thumb components.Syncing Inputs:
x-hui::range-slider.input to sync thumb values with native inputs:
<x-hui::range-slider.input role="min" class="w-16"/>
<span data-hui-range-slider-value="min"></span>
Form Integration:
name attribute:
<x-hui::range-slider.thumb role="min" name="price_min" value="{{ old('price_min', 20) }}"/>
min, max).Conditional Rendering:
@if to toggle components dynamically:
@if(auth()->user()->can('edit_profile'))
<x-hui::tabs.tab>Edit Profile</x-hui::tabs.tab>
@endif
Accessibility:
aria-disabled="true" for disabled tabs).ArrowLeft/ArrowRight for tabs.layer(base) for HUI CSS to avoid specificity conflicts:
@import '../../vendor/schaefersoft/laravel-headless-ui/resources/css/hui.css' layer(base);
import '../../vendor/schaefersoft/laravel-headless-ui/dist/js/hui.js';
import '../../vendor/schaefersoft/laravel-headless-ui/resources/js/hui.ts';
Thumb Role Requirement:
role is required for x-hui::range-slider.thumb (must be "min" or "max").ThumbRole enum or strings:
<x-hui::range-slider.thumb role="min" .../>
Panel Order Mismatch:
tabs.tab and tabs.panel are in the same sequence.CSS Specificity:
!important sparingly or increase specificity:
.my-tabs .hui-tabs-tab[data-active] { ... }
Disabled State:
data-disabled or aria-disabled in CSS:
<x-hui::tabs.tab data-disabled>...</x-hui::tabs.tab>
[data-disabled] { opacity: 0.5; }
Console Errors:
role attributes or invalid props.Invalid role "foo" for thumb. Must be "min" or "max".Initial Index Fallback:
:initial-index is invalid, the first enabled tab activates.{{ dd($tabs->initialIndex) }} to verify the value.Slider Value Sync:
data-hui-range-slider-value elements don’t update, ensure:
role matches the thumb (e.g., data-hui-range-slider-value="min").No Global Config:
Vertical Tabs:
:vertical="true" and update keyboard navigation expectations (use ArrowUp/ArrowDown).Thumb Styling:
<input type="range"> thumbs require CSS pseudo-elements:
.hui-range-slider-thumb::-webkit-slider-thumb {
appearance: none;
width: 20px;
height: 20px;
background: #4f46e5;
}
Custom Components:
resources/views/vendor/schaefersoft/headless-ui.resources/views/components/range-slider.blade.php and modify.JavaScript Hooks:
document.addEventListener('hui:tab:change', (e) => {
console.log('Active tab changed:', e.detail.index);
});
Tailwind Variants:
data-* variants for dynamic styling:
<x-hui::tabs.tab class="data-[active]:bg-blue-500">...</x-hui::tabs.tab>
How can I help you explore Laravel packages today?