# Test numeric scale
assert is_numeric_scale(4) == True
assert is_numeric_scale(2.5) == True
assert is_numeric_scale("px") == True
assert is_numeric_scale("auto") == Falsebase
Core Types
Define the fundamental types used throughout the library:
Value Validators
Functions to validate and identify different types of Tailwind values:
is_numeric_scale
def is_numeric_scale(
value:Any, # The value to check - can be int, float, or string
)->bool: # True if the value is a valid numeric scale, False otherwise
Check if value is a valid numeric scale (int, float, or ‘px’).
is_fraction
def is_fraction(
value:Any, # The value to check for fraction format
)->bool: # True if the value is a valid fraction string, False otherwise
Check if value is a valid fraction string (e.g., ‘1/2’, ‘3/4’).
is_custom_property
def is_custom_property(
value:Any, # The value to check for CSS custom property format
)->bool: # True if the value is a CSS custom property, False otherwise
Check if value is a CSS custom property (starts with –).
is_arbitrary_value
def is_arbitrary_value(
value:Any, # The value to check for arbitrary CSS value format
)->bool: # True if the value contains CSS units or calc(), False otherwise
Check if value is an arbitrary value (contains units or special chars).
Base Protocol
Define the protocol that all utility builders must implement:
TailwindBuilder
def TailwindBuilder(
args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):
Protocol for all Tailwind utility builders.
Base Classes
Abstract base classes for different types of utility builders:
BaseUtility
def BaseUtility(
prefix:str, # The utility prefix (e.g., 'w' for width, 'p' for padding)
):
Base class for all Tailwind utility builders.
Standard Value Formatter
A standard implementation for formatting Tailwind values:
ModifierMixin
def ModifierMixin(
args:VAR_POSITIONAL, kwargs:VAR_KEYWORD
):
Mixin to add modifier support to any utility with convenient property access.
Modifier Definitions
Comprehensive definitions of all Tailwind CSS modifiers/variants:
ModifierGroup
def ModifierGroup(
name:str, description:str, modifiers:Dict
)->None:
Group of related modifiers with descriptions.
StandardUtility
def StandardUtility(
prefix:str, # The utility prefix (e.g., 'w' for width, 'p' for padding)
):
Standard utility class with common value formatting and modifier support.
Named Scale Utilities
For utilities that support named scales (e.g., sm, md, lg):
NamedScale
def NamedScale(
name:str, var:Optional=None, comment:Optional=None
)->None:
Represents a named scale with optional CSS variable.
Modifier Support
Support for responsive and state modifiers:
Breakpoint
def Breakpoint(
name:str, min_width:Optional=None
)->None:
Responsive breakpoint definition.
Base Factory with Documentation
A base factory class that all factories inherit from, providing documentation support:
BaseFactory
def BaseFactory(
doc:str, # Documentation string describing what this factory creates
):
Initialize with documentation string.
Utility Factory
A factory function to create utility instances with method chaining:
UtilityFactory
def UtilityFactory(
utility_class:type, # The utility class to instantiate
prefix:str, # The prefix to use for the utilities
doc:Optional=None, # Optional documentation string
):
Factory for creating utility instances with fluent API.
Examples
Let’s test the base architecture with some examples:
# Test fraction detection
assert is_fraction("1/2") == True
assert is_fraction("3/4") == True
assert is_fraction("1.5") == False
assert is_fraction("full") == False# Test custom property detection
assert is_custom_property("--spacing-lg") == True
assert is_custom_property("--color-primary") == True
assert is_custom_property("spacing-lg") == False# Test arbitrary value detection
assert is_arbitrary_value("10px") == True
assert is_arbitrary_value("2.5rem") == True
assert is_arbitrary_value("100%") == True
assert is_arbitrary_value("calc(100% - 20px)") == True
assert is_arbitrary_value("auto") == False# Test StandardUtility class
class TestUtility(StandardUtility):
pass
# Create test instances
util = TestUtility("w")
# Test different value types
assert util.build(4) == "w-4"
assert util.build("1/2") == "w-1/2"
assert util.build("--custom") == "w-(--custom)"
assert util.build("10px") == "w-[10px]"
assert util.build("auto") == "w-auto"# Test UtilityFactory
w = UtilityFactory(TestUtility, "w")
# Test factory patterns
assert str(w(4)) == "w-4"
assert str(w.full) == "w-full"
assert str(w.auto) == "w-auto"
assert str(w.screen) == "w-screen"Test Modifiers
Test the modifier support on utilities:
# First, let's update TestUtility to inherit from StandardUtility instead
class TestUtilityWithModifiers(StandardUtility):
pass
# Test basic modifier application
util = TestUtilityWithModifiers("bg")
util._value = "red-500"
# Test single modifiers
assert str(util.hover) == "hover:bg-red-500"
assert str(util.focus) == "focus:bg-red-500"
assert str(util.dark) == "dark:bg-red-500"
# Test chained modifiers
assert str(util.hover.dark) == "dark:hover:bg-red-500"
assert str(util.md.hover) == "hover:md:bg-red-500"
assert str(util.sm.hover.dark) == "dark:hover:sm:bg-red-500"
# Test responsive modifiers
assert str(util.sm) == "sm:bg-red-500"
assert str(util.md) == "md:bg-red-500"
assert str(util.lg) == "lg:bg-red-500"
assert str(util._2xl) == "2xl:bg-red-500"
# Test pseudo-element modifiers
assert str(util.before) == "before:bg-red-500"
assert str(util.after) == "after:bg-red-500"
assert str(util.placeholder) == "placeholder:bg-red-500"
# Test structural modifiers
assert str(util.first) == "first:bg-red-500"
assert str(util.last) == "last:bg-red-500"
assert str(util.odd) == "odd:bg-red-500"
assert str(util.even) == "even:bg-red-500"
print("✅ Basic modifier tests passed!")✅ Basic modifier tests passed!
# Test group and peer modifiers
assert str(util.group()) == "group:bg-red-500"
assert str(util.group("hover")) == "group-hover:bg-red-500"
assert str(util.group("focus", "sidebar")) == "group/sidebar-focus:bg-red-500"
assert str(util.peer()) == "peer:bg-red-500"
assert str(util.peer("checked")) == "peer-checked:bg-red-500"
assert str(util.peer("invalid", "email")) == "peer/email-invalid:bg-red-500"
# Test arbitrary modifiers
assert str(util.has("input:checked")) == "has-[input:checked]:bg-red-500"
assert str(util.aria("checked")) == "aria-checked:bg-red-500"
assert str(util.aria("sort", "ascending")) == "aria-[sort=ascending]:bg-red-500"
assert str(util.data("active")) == "data-[active]:bg-red-500"
assert str(util.data("state", "open")) == "data-[state=open]:bg-red-500"
assert str(util.arbitrary("&.is-dragging")) == "[&.is-dragging]:bg-red-500"
print("✅ Group/peer and arbitrary modifier tests passed!")✅ Group/peer and arbitrary modifier tests passed!
Class Combination Utility
A utility function to combine multiple class builders:
combine_classes
def combine_classes(
args:Union
)->str: # Space-separated class string
Combine multiple class builders or strings into a single class string.
# Test combine_classes
w_factory = UtilityFactory(TestUtility, "w")
h_factory = UtilityFactory(TestUtility, "h")
result = combine_classes(
w_factory(4),
h_factory.full,
"flex",
None,
"items-center"
)
assert result == "w-4 h-full flex items-center"class TestUtilityWithModifiers(StandardUtility):
pass
# Test combine_classes with modifiers
w_hover = TestUtilityWithModifiers("w")
w_hover._value = "full"
w_hover = w_hover.hover
h_dark = TestUtilityWithModifiers("h")
h_dark._value = "screen"
h_dark = h_dark.dark.md
result = combine_classes(
w_hover,
h_dark,
"flex",
None,
"items-center"
)
assert result == "hover:w-full md:dark:h-screen flex items-center"
print("✅ combine_classes with modifiers test passed!")✅ combine_classes with modifiers test passed!
Practical Examples with FastHTML
Comprehensive examples showing modifiers in action:
# Example: Interactive button with hover, focus, and active states
from fasthtml.common import Button
class TestUtilityWithModifiers(StandardUtility):
pass
# Create a utility instance with modifiers
bg_base = TestUtilityWithModifiers("bg")
bg_base._value = "blue-500"
bg_hover = TestUtilityWithModifiers("bg")
bg_hover._value = "blue-600"
bg_active = TestUtilityWithModifiers("bg")
bg_active._value = "blue-700"
# Create button with multiple states
button = Button(
"Click me",
cls=combine_classes(
bg_base,
bg_hover.hover,
bg_active.active,
"text-white px-4 py-2 rounded"
)
)
assert button.attrs['class'] == "bg-blue-500 hover:bg-blue-600 active:bg-blue-700 text-white px-4 py-2 rounded"
print("✅ Interactive button example passed!")✅ Interactive button example passed!
# Example: Responsive layout with dark mode support
from fasthtml.common import Div, H1, P
class TestUtilityWithModifiers(StandardUtility):
pass
# Create utilities with responsive and dark mode modifiers
padding = TestUtilityWithModifiers("p")
padding._value = "4"
padding_md = TestUtilityWithModifiers("p")
padding_md._value = "8"
bg_light = TestUtilityWithModifiers("bg")
bg_light._value = "white"
bg_dark = TestUtilityWithModifiers("bg")
bg_dark._value = "gray-900"
text_light = TestUtilityWithModifiers("text")
text_light._value = "gray-900"
text_dark = TestUtilityWithModifiers("text")
text_dark._value = "white"
# Create responsive card component
card = Div(
H1("Responsive Card", cls=combine_classes(text_light, text_dark.dark)),
P("This card adapts to screen size and color scheme."),
cls=combine_classes(
padding,
padding_md.md,
bg_light,
bg_dark.dark,
"rounded-lg shadow"
)
)
assert card.attrs['class'] == "p-4 md:p-8 bg-white dark:bg-gray-900 rounded-lg shadow"
assert card.children[0].attrs['class'] == "text-gray-900 dark:text-white"
print("✅ Responsive dark mode example passed!")✅ Responsive dark mode example passed!
# Example: Form input with various states
from fasthtml.common import Input, Label, Span
class TestUtilityWithModifiers(StandardUtility):
pass
# Create utilities for form states
border_base = TestUtilityWithModifiers("border")
border_base._value = "gray-300"
border_focus = TestUtilityWithModifiers("border")
border_focus._value = "blue-500"
border_invalid = TestUtilityWithModifiers("border")
border_invalid._value = "red-500"
# Create form input with label
form_field = Label(
Span("Email", cls="block text-sm font-medium mb-1"),
Input(
type="email",
required=True,
cls=combine_classes(
"w-full px-3 py-2 rounded-md",
border_base,
border_focus.focus,
border_invalid.invalid,
"outline-none focus:ring-2 focus:ring-blue-500/20"
)
)
)
assert "border-gray-300" in form_field.children[1].attrs['class']
assert "focus:border-blue-500" in form_field.children[1].attrs['class']
assert "invalid:border-red-500" in form_field.children[1].attrs['class']
print("✅ Form states example passed!")✅ Form states example passed!
Single Value Factory
A factory for standalone utility class strings:
SingleValueUtility
def SingleValueUtility(
value:str, # The complete utility class string (e.g., "container", "sr-only")
):
A utility that represents a single fixed value.
SingleValueFactory
def SingleValueFactory(
value:str, # The utility class string (e.g., "container")
doc:str, # Documentation describing what this utility does
):
Factory for a single utility class with modifier support.
# Test SingleValueFactory
container = SingleValueFactory(
"container",
"Responsive container with breakpoint-based max-widths"
)
# Test various ways to use it
assert str(container) == "container"
assert str(container()) == "container" # Now returns a utility instance
assert container.build() == "container"
assert container.describe() == "Responsive container with breakpoint-based max-widths"
# Test with modifiers
assert str(container.hover) == "hover:container"
assert str(container.md) == "md:container"
assert str(container.dark) == "dark:container"
# Test chained modifiers
assert str(container.hover.md) == "md:hover:container"
assert str(container.dark.lg) == "lg:dark:container"
# Test calling with modifiers
container_util = container()
assert str(container_util.hover) == "hover:container"
assert str(container_util.focus.dark) == "dark:focus:container"
# Test in combine_classes
result = combine_classes(container, "mx-auto", "px-4")
assert result == "container mx-auto px-4"
# Test with modifiers in combine_classes
result = combine_classes(container.hover, container.md, "mx-auto")
assert result == "hover:container md:container mx-auto"
print("✅ SingleValueFactory with modifiers tests passed!")✅ SingleValueFactory with modifiers tests passed!
Directional Utilities
Support for utilities with directional variants (top, right, bottom, left):
Direction
def Direction(
suffix:str, css_suffix:str
)->None:
Represents a directional variant.
DirectionalUtility
def DirectionalUtility(
prefix:str, # Base prefix (e.g., 'p' for padding)
direction:Optional=None, # Optional direction ('t', 'r', 'b', 'l', 'x', 'y')
):
Base class for utilities with directional variants.
# Test directional utilities
pt = DirectionalUtility("p", "t")
assert pt.build(4) == "pt-4"
px = DirectionalUtility("p", "x")
assert px.build(8) == "px-8"Negative Value Support
Support for utilities that can have negative values:
NegativeableUtility
def NegativeableUtility(
prefix:str, # Base prefix
negative:bool=False, # Whether this is a negative variant
):
Utility class that supports negative values.