A modern, classless CSS framework that pairs perfectly with SigPro reactive components. Write clean semantic HTML with zero classes and get beautiful, responsive styling with dark mode support.
- Classless β works with semantic HTML and SigPro components, no extra classes needed
- Dark mode β automatic system preference detection + manual data-theme override
- Modern form controls β animated checkboxes, radios, toggle switches, and range sliders
- Smooth animations β accordions, dialogs, drawers, sheets, and sidebars with elegant transitions
- Fully responsive β mobile-first design that works on all devices
- Accessibility β focus states, reduced motion support, and proper contrast ratios
- SigPro native β designed to work seamlessly with SigPro's reactive syntax
Add the CSS file to your HTML:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/natxocc/sigpro-css@latest/sigpro.min.css">Include SigPro runtime (all functions are auto-assigned to window):
<script src="https://unpkg.com/sigpro"></script>That's it! All SigPro functions ($, $if, $for, $watch, $mount, etc.) and HTML helpers (Div, P, H1, Button, etc.) are available globally.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/natxocc/sigpro-css@latest/sigpro.min.css">
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/sigpro"></script>
<script>
// All SigPro functions are already available globally
// No need to import or destructure anything!
const App = () => {
const name = $("");
const theme = $("light");
const notifications = $(false);
const volume = $(50);
const items = $(["Item 1", "Item 2", "Item 3"]);
return Div({ class: "container" }, [
Header([
H1("SigPro CSS Demo"),
P("No classes needed β just clean reactive components")
]),
Form([
// Reactive input with two-way binding
Input({
type: "text",
placeholder: "Your name",
value: name,
oninput: (e) => name(e.target.value)
}),
P(() => `Hello, ${name() || "stranger"}!`),
// Theme selector with radio buttons
Fieldset([
Legend("Theme"),
Label([
Input({
type: "radio",
name: "theme",
value: "light",
checked: () => theme() === "light",
onchange: (e) => theme(e.target.value)
}),
" Light"
]),
Label([
Input({
type: "radio",
name: "theme",
value: "dark",
checked: () => theme() === "dark",
onchange: (e) => theme(e.target.value)
}),
" Dark"
])
]),
// Toggle switch (iOS-style)
Label([
Input({
type: "checkbox",
class: "toggle",
checked: notifications,
onchange: (e) => notifications(e.target.checked)
}),
" Enable notifications"
]),
// Range slider with live value
Label([
"Volume: ",
Input({
type: "range",
min: 0,
max: 100,
value: volume,
oninput: (e) => volume(e.target.valueAsNumber)
}),
() => `${volume()}%`
]),
// Modern checkbox
Label([
Input({ type: "checkbox", checked: () => false }),
" Accept terms and conditions"
]),
// Modern radio group
Fieldset([
Legend("Priority"),
Label([Input({ type: "radio", name: "priority", value: "low" }), " Low"]),
Label([Input({ type: "radio", name: "priority", value: "medium" }), " Medium"]),
Label([Input({ type: "radio", name: "priority", value: "high" }), " High"])
]),
// Button group
Div({ style: "display: flex; gap: 0.5rem" }, [
Button({ type: "submit" }, "Submit"),
Button({ type: "button", secondary: true }, "Cancel"),
Input({ type: "reset", value: "Reset" })
]),
// Conditional rendering
$if(notifications,
Div({ class: "alert" }, "β
Notifications are enabled"),
Div({ class: "info" }, "π Notifications are disabled")
),
// List rendering
H3("Your items:"),
Ul(
$for(items, (item, index) => Li({ key: index }, item))
),
// Button to add items
Button({
onclick: () => items([...items(), `Item ${items().length + 1}`])
}, "Add Item"),
// Animated accordion
Details([
Summary("Click to expand"),
P("This content slides open with a smooth animation"),
P("Works with any HTML inside"),
Code("$if(condition, trueView, falseView)")
]),
// Animated modal dialog
Button({
onclick: () => document.getElementById("demoModal").showModal()
}, "Open Modal"),
Dialog({ id: "demoModal" }, [
H3("Modal Dialog"),
P("This modal has smooth scale animation"),
Button({ onclick: () => document.getElementById("demoModal").close() }, "Close")
]),
// Animated drawer (bottom sheet)
Button({
onclick: () => document.getElementById("demoDrawer").showModal()
}, "Open Drawer"),
Dialog({ id: "demoDrawer", drawer: true }, [
H3("Bottom Drawer"),
P("Slides up from the bottom with smooth animation"),
Button({ onclick: () => document.getElementById("demoDrawer").close() }, "Close")
])
]),
// Watch theme changes and update HTML attribute
$watch(theme, (val) => {
document.documentElement.setAttribute("data-theme", val);
})
]);
};
// Mount the app to the DOM
$mount(App, "#app");
</script>
</body>
</html>$(initialValue)β create a reactive signal$watch(signal, callback)β react to signal changes$if(condition, trueView, falseView)β conditional rendering$for(array, renderFn)β list rendering
All standard HTML tags are available as functions:
Div(),Span(),P(),H1()throughH6()Header(),Footer(),Section(),Article(),Aside(),Nav()Form(),Input(),Button(),Select(),Textarea(),Label()Ul(),Ol(),Li(),Table(),Tr(),Td(),Th()Dialog(),Details(),Summary(),Progress()- And many more...
$mount(component, selector)β mount reactive component to DOM$router(routes)β hash-based router with reactive views$html(tag, props, children)β low-level element creator
Input({ type: "checkbox", checked: isChecked, onchange: (e) => isChecked(e.target.checked) })Input({ type: "radio", name: "group", value: "option1", checked: () => selected() === "option1" })Add class: "toggle" to any checkbox:
Input({ type: "checkbox", class: "toggle", checked: enabled, onchange: (e) => enabled(e.target.checked) })Input({ type: "range", min: 0, max: 100, value: volume, oninput: (e) => volume(e.target.valueAsNumber) })Details([
Summary("Click to expand"),
P("Content slides open smoothly")
])// Modal
Dialog({ id: "modal" }, [/* content */])
// Drawer (bottom sheet)
Dialog({ id: "drawer", drawer: true }, [/* content */])
// Sheet from right
Dialog({ id: "sheet", "sheet-right": true }, [/* content */])Add tooltip attributes to any element:
Button({ "tooltip-top": "Click me!" }, "Hover")The CSS automatically follows your system's color scheme. Override with data-theme:
$watch(theme, (val) => {
document.documentElement.setAttribute("data-theme", val);
});Available themes: "light", "dark"
Customize colors by overriding these variables in your own CSS:
:root {
--radius: 0.5rem;
--background: oklch(1 0 0);
--foreground: oklch(0.141 0.005 285.823);
--primary: oklch(0.21 0.006 285.885);
--secondary: oklch(0.967 0.001 286.375);
--destructive: oklch(0.577 0.245 27.325);
--border-color: oklch(0.92 0.004 286.32);
--shadow: 0px 10px 15px -3px rgba(0,0,0,0.1);
}- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
MIT License
SigPro CSS β Modern classless styling for SigPro reactive components.