beartropy/ui
Beartropy UI is a small Laravel UI package providing ready-made components and helpers to speed up building admin and front-end screens. Drop in common layouts, forms, and UI utilities to get a consistent look fast with minimal setup.
<x-bt-theme-head />
ThemeHead extends BeartropyComponenttheme-head.blade.php<style> + <script> tag<x-bt-toggle-theme /> — prevents FOUC (Flash of Unstyled Content)Outputs a blocking inline <style> + <script> that applies the saved dark/light theme to <html> before any CSS or body content renders. Without this component, pages flash light then switch to dark when the JS bundle loads.
Note: If you use [@BeartropyAssets](https://github.com/BeartropyAssets), the inline theme style and script are already included automatically. You only need <x-bt-theme-head /> if you load Beartropy assets manually (e.g., via [@vite](https://github.com/vite)) or need the script earlier in <head>.
Must be placed in <head> before stylesheets.
None. This component takes no props.
None.
<style data-navigate-once>
html.dark { color-scheme: dark }
html:not(.dark) { color-scheme: light }
</style>
<script data-navigate-once>
(IIFE)
├── Read localStorage.getItem('theme')
├── Check window.matchMedia('(prefers-color-scheme:dark)')
├── Toggle 'dark' class on <html>
├── Set document.documentElement.style.colorScheme
├── Set bt_theme cookie (for [@beartropyHtmlClass](https://github.com/beartropyHtmlClass) server-side rendering)
└── Register MutationObserver on <html> class attribute
└── If wire:navigate morphs <html> and strips 'dark', reapply before repaint
</script>
<style> sets color-scheme: dark on html.dark and color-scheme: light on html:not(.dark) — applies via CSS immediately, no JS needed<script> runs synchronously in <head> — reads localStorage.theme or falls back to prefers-color-scheme media query, toggles dark class and colorScheme on <html>bt_theme cookie (enables server-side rendering via [@beartropyHtmlClass](https://github.com/beartropyHtmlClass))MutationObserver (guarded by window.__btThemeGuard) on <html> class attribute — catches Livewire wire:navigate morphing the class and reapplies the correct theme before the browser repaints<style> and <script> have data-navigate-once — Livewire preserves them across SPA navigations without removal/re-addition<x-bt-toggle-theme />| Component | Role |
|---|---|
<x-bt-theme-head /> |
Prevents FOUC — apply theme before paint |
<x-bt-toggle-theme /> |
UI toggle — lets user switch theme |
Both are independent. theme-head is needed even without a visible toggle (e.g., if theme is set via a settings page or window.__setTheme()).
[@beartropyHtmlClass](https://github.com/beartropyHtmlClass)For zero-FOUC server-side rendering, use this directive on your <html> tag:
<html lang="en" class="[@beartropyHtmlClass](https://github.com/beartropyHtmlClass)">
Reads the bt_theme cookie (set by the inline script and toggle component) and outputs dark if the user prefers dark mode. The browser receives <html class="dark"> in the initial HTML — no JS dependency for the first paint.
{{-- Standard layout setup --}}
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<x-bt-theme-head />
[@vite](https://github.com/vite)(['resources/css/app.css', 'resources/js/app.js'])
</head>
{{-- With Livewire + wire:navigate --}}
<head>
<x-bt-theme-head />
[@livewireStyles](https://github.com/livewireStyles)
[@vite](https://github.com/vite)(['resources/css/app.css', 'resources/js/app.js'])
</head>
{{-- Zero-FOUC server-side rendering --}}
<html lang="en" class="[@beartropyHtmlClass](https://github.com/beartropyHtmlClass)">
<head>
<x-bt-theme-head />
[@vite](https://github.com/vite)(['resources/css/app.css', 'resources/js/app.js'])
</head>
<head> — placing it in <body> defeats the purpose (content already rendered)dark class must be present when CSS is parsed<style> + <script> tagwindow.__btThemeGuardinitTheme() in beartropy-ui.js still works as a fallback if this component is not useddata-navigate-once prevents Livewire from removing the tags during wire:navigate head mergingHow can I help you explore Laravel packages today?