base

Base classes, types, and protocols for Tailwind CSS abstractions

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 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") == False
# 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.