A Tailwind CSS JIT compiler for s&box.
TailBox brings the power of Tailwind CSS utility classes directly into the s&box UI engine. No Node.js, no CLI, no external build steps. You type the classes in your .razor files, and TailBox compiles them instantly in C#.
Unlike other static generation tools (such as Sailwind), TailBox is a true Just-In-Time (JIT) compiler. It reads your UI at runtime, parses complex arbitrary values (e.g. w-[25px]), understands chained variants (e.g. dark:hover:bg-red-500/50), and translates them into optimal s&box styles natively.
- v1.2.0 - Intelligent Merging: Integration of the
TailboxMergestandalone library for professional-grade class conflict resolution. - Optimized JIT Engine: Designed to minimize string allocations in hot paths, reducing GC pressure and maintaining UI performance.
- Tailwind Syntax Support: Supports variants (
hover:,active:), arbitrary values (w-[25px],bg-[#ff0000]), and opacity modifiers (bg-red-500/50). - Hot-Reload Compatible: Works perfectly with s&box UI hot-reloading. CSS is generated incrementally in milliseconds.
- Smart Transitions & Animations: Automatically converts Tailwind durations and easings into s&box-compatible UI animations.
- Native Theming: Supports Light/Dark modes natively mapped to s&box UI, saving preferences automatically to Cookies.
Add TailBox CSS Compiler to your project dependencies via the s&box Library Manager (search for tailbox).
TailBox relies on standard CSS variables for its colors (ex: bg-primary, text-muted-foreground).
Create a globals.scss file in your code/ folder to define your theme colors. You can use any Shadcn UI Theme or generate your own stunning palettes using tools like Tweakcn, just drop the CSS variables inside!
⚠️ CRITICAL: RGB Format Required
To support Tailwind's opacity modifiers (e.g.bg-primary/50), all your CSS color variables must be defined inrgb(r, g, b)format. Hex codes or HSL will not work properly with opacity.
/* globals.scss */
/* @tailbox-default-mode: dark */
:root {
--background: rgb(255, 255, 255);
--foreground: rgb(10, 10, 10);
--card: rgb(255, 255, 255);
--card-foreground: rgb(10, 10, 10);
--popover: rgb(255, 255, 255);
--popover-foreground: rgb(10, 10, 10);
--primary: rgb(23, 23, 23);
--primary-foreground: rgb(250, 250, 250);
--secondary: rgb(245, 245, 245);
--secondary-foreground: rgb(23, 23, 23);
--muted: rgb(245, 245, 245);
--muted-foreground: rgb(115, 115, 115);
--accent: rgb(245, 245, 245);
--accent-foreground: rgb(23, 23, 23);
--destructive: rgb(231, 0, 11);
--destructive-foreground: rgb(255, 255, 255);
--border: rgb(229, 229, 229);
--input: rgb(229, 229, 229);
--ring: rgb(161, 161, 161);
--radius: 0.625rem;
/* ... add your other specific variables ... */
}
.dark {
--background: rgb(10, 10, 10);
--foreground: rgb(250, 250, 250);
--card: rgb(23, 23, 23);
--card-foreground: rgb(250, 250, 250);
--popover: rgb(38, 38, 38);
--popover-foreground: rgb(250, 250, 250);
--primary: rgb(229, 229, 229);
--primary-foreground: rgb(23, 23, 23);
--secondary: rgb(38, 38, 38);
--secondary-foreground: rgb(250, 250, 250);
--muted: rgb(38, 38, 38);
--muted-foreground: rgb(161, 161, 161);
--accent: rgb(64, 64, 64);
--accent-foreground: rgb(250, 250, 250);
--destructive: rgb(255, 100, 103);
--destructive-foreground: rgb(250, 250, 250);
--border: rgb(40, 40, 40);
--input: rgb(52, 52, 52);
--ring: rgb(115, 115, 115);
--radius: 0.625rem;
/* ... */
}Instead of inheriting from Panel, simply inherit your main HUD or Menu from TailboxPanel. This only needs to be done once at the root level of your UI!
Important Setup Rule: Your root structure should use
<root>for pointer events, and an inner<div>withbg-backgroundto properly process the color theme changes.
@using Sandbox;
@using Sandbox.UI;
@using Tailbox.Compiler;
@inherits TailboxPanel
<root class="absolute inset-0 pointer-events-auto">
<!-- App Background -->
<div class="absolute inset-0 bg-background flex flex-col items-center justify-center p-8">
<!-- Main Elegant Card -->
<div class="flex flex-col bg-card border border-border rounded-2xl shadow-xl w-[600px] shrink-0 overflow-hidden transform transition-all duration-300">
<!-- Hero Header -->
<div class="flex flex-col p-10 bg-muted/40 border-b border-border/50 items-center justify-center">
<div class="w-[80px] h-[80px] bg-primary/20 rounded-full flex items-center justify-center border border-primary/30 shadow-sm mb-21">
<label class="text-3xl font-black text-primary font-mono select-none">TB</label>
</div>
<label class="text-[48px] font-black text-foreground font-sans tracking-tight mb-2">Hello TailBox!</label>
<label class="text-muted-foreground font-medium text-[18px] font-sans text-center">
A Tailbox CSS JIT Compiler for s&box.
</label>
</div>
<!-- Content Component -->
<div class="flex flex-col p-8 items-center gap-8 bg-card">
<NestedComponent />
<!-- Action Buttons -->
<div class="flex flex-row gap-4 mt-2 w-full justify-center">
<button class="flex items-center justify-center bg-primary hover:bg-primary/90 text-primary-foreground px-8 py-3.5 rounded-full font-bold shadow-md transition-all hover:scale-105 active:scale-95 shrink-0 text-base cursor-pointer" onclick=@ToggleTheme>
Toggle Theme Mode
</button>
</div>
</div>
</div>
</div>
</root>
@code {
protected override int BuildHash() => HashCode.Combine(TailboxRuntime.CurrentTheme);
void ToggleTheme() => TailboxRuntime.ToggleTheme();
}For any child component inside your project (or in sub-folders like UI/Components/), you should inherit from TailboxWidget instead of the standard Panel.
💡 Why
TailboxWidget?
If you inherit from a standardPanel, creating new classes during Hot-Reload might not translate them until the parent updates.TailboxWidgetisolates the child component, allowing it to translate its own new classes immediately upon Hot-Reload or state changes, ensuring a consistent development experience.
✨ Pro Tip: Global Usings
To avoid typing@using Tailbox.Compiler;at the top of every Razor file, create aGlobalUsings.csfile anywhere in yourCode/folder with this single line:global using System; global using System.Collections.Generic; global using System.Linq; global using Tailbox.Compiler;
@using Sandbox;
@using Sandbox.UI;
@using Tailbox.Compiler;
@inherits TailboxWidget
<root class="flex p-4 bg-muted rounded-md text-foreground hover:bg-muted/80 transition-colors">
<label>I'm fully Hot-Reload compatible!</label>
</root>TailBox has a powerful built-in TailboxRuntime.SetTheme("dark") system.
- When the theme is changed, it is automatically saved as a persistent Cookie (
Tailbox_theme). - Next time the player launches the game, TailBox remembers their choice and applies the dark/light mode before the first frame.
- Changing a theme automatically forces s&box to restyle all components instantly.
TailBox goes beyond simple classes by supporting variant chaining. All of these work out-of-the-box natively in s&box:
hover:bg-blue-500active:scale-95dark:bg-blackgroup-hover:text-primary
- Utility classes and naming conventions are inspired by Tailwind CSS.
- Open Source and custom-built from scratch for the s&box engine.
TailBox CSS Compiler is licensed under the MIT license.
Feel free to contribute on GitHub to help improve this library!
Last reviewed: March 2026