Transition Property
Control which CSS properties transition:
TransitionPropertyFactory
def TransitionPropertyFactory(
values_dict:Optional= None , # Dictionary mapping attribute names to CSS values
doc:Optional= None , # Optional documentation string
):
Factory for transition property utilities with custom value support.
TransitionPropertyFactory
def TransitionPropertyFactory(
values_dict:Optional= None , # Dictionary mapping attribute names to CSS values
doc:Optional= None , # Optional documentation string
):
Factory for transition property utilities with custom value support.
Exported source
# Create transition property factory
transition = TransitionPropertyFactory(
{
"" : "transition" , # Default transition
"all" : "transition-all" ,
"colors" : "transition-colors" ,
"opacity" : "transition-opacity" ,
"shadow" : "transition-shadow" ,
"transform" : "transition-transform" ,
"none" : "transition-none"
},
"Transition property utilities for controlling which CSS properties transition"
) # The transition property factory
test_transitions_and_animation_property_examples
def test_transitions_and_animation_property_examples(
):
Test transition property utilities.
Exported source
# Recreate transition property factory with the enhanced class
transition = TransitionPropertyFactory(
{
"" : "transition" , # Default transition
"all" : "transition-all" ,
"colors" : "transition-colors" ,
"opacity" : "transition-opacity" ,
"shadow" : "transition-shadow" ,
"transform" : "transition-transform" ,
"none" : "transition-none"
},
"Transition property utilities for controlling which CSS properties transition"
) # The transition property factory
Exported source
def test_transitions_and_animation_property_examples():
"""Test transition property utilities."""
# Test predefined transition properties
assert str (transition.default) == "transition"
assert str (transition.all ) == "transition-all"
assert str (transition.colors) == "transition-colors"
assert str (transition.opacity) == "transition-opacity"
assert str (transition.shadow) == "transition-shadow"
assert str (transition.transform) == "transition-transform"
assert str (transition.none) == "transition-none"
# Test custom properties
assert transition("--my-transition" ) == "transition-(--my-transition)"
assert transition("--custom-props" ) == "transition-(--custom-props)"
# Test arbitrary values
assert transition("width" ) == "transition-[width]"
assert transition("width, height" ) == "transition-[width, height]"
assert transition("opacity 0.3s, transform 0.3s" ) == "transition-[opacity 0.3s, transform 0.3s]"
# Run the tests
test_transitions_and_animation_property_examples()
Transition Behavior
Control the behavior of CSS transitions:
test_transitions_and_animation_behavior_examples
def test_transitions_and_animation_behavior_examples(
):
Test transition behavior utilities.
Exported source
transition_behavior = SimpleFactory(
{
"normal" : "transition-normal" ,
"discrete" : "transition-discrete"
},
"Transition behavior utilities for controlling the behavior of CSS transitions"
) # The transition behavior factory
Exported source
def test_transitions_and_animation_behavior_examples():
"""Test transition behavior utilities."""
assert str (transition_behavior.normal) == "transition-normal"
assert str (transition_behavior.discrete) == "transition-discrete"
# Run the tests
test_transitions_and_animation_behavior_examples()
Transition Duration
Control the duration of CSS transitions:
DurationFactory
def DurationFactory(
prefix:str , config:ScaleConfig, doc:Optional= None
):
Factory for duration utilities with millisecond support.
Exported source
# Standard duration values in milliseconds
DURATION_SCALE = [0 , 75 , 100 , 150 , 200 , 300 , 500 , 700 , 1000 ] # Standard Tailwind duration scale
Exported source
DURATION_CONFIG = ScaleConfig( # Duration configuration
numeric= False , # Don't use full numeric scale
decimals= False ,
fractions= False ,
named= None ,
special= {
"0" : "0" ,
"75" : "75" ,
"100" : "100" ,
"150" : "150" ,
"200" : "200" ,
"300" : "300" ,
"500" : "500" ,
"700" : "700" ,
"1000" : "1000" ,
"initial" : "initial"
},
negative= False
)
Exported source
# Create duration factory
duration = DurationFactory("duration" , DURATION_CONFIG, "Transition duration utilities for controlling the duration of CSS transitions" ) # The duration factory
test_transitions_and_animation_duration_examples
def test_transitions_and_animation_duration_examples(
):
Test transition duration utilities.
Exported source
def test_transitions_and_animation_duration_examples():
"""Test transition duration utilities."""
# Test standard duration values with attributes
assert str (duration._0) == "duration-0"
assert str (duration._75) == "duration-75"
assert str (duration._100) == "duration-100"
assert str (duration._150) == "duration-150"
assert str (duration._200) == "duration-200"
assert str (duration._300) == "duration-300"
assert str (duration._500) == "duration-500"
assert str (duration._700) == "duration-700"
assert str (duration._1000) == "duration-1000"
assert str (duration.initial) == "duration-initial"
# Test all attributes are available for autocomplete
assert hasattr (duration, '_0' )
assert hasattr (duration, '_75' )
assert hasattr (duration, '_100' )
assert hasattr (duration, '_150' )
assert hasattr (duration, '_200' )
assert hasattr (duration, '_300' )
assert hasattr (duration, '_500' )
assert hasattr (duration, '_700' )
assert hasattr (duration, '_1000' )
assert hasattr (duration, 'initial' )
# Verify they are ScaledUtility instances
assert isinstance (duration._300, ScaledUtility)
assert isinstance (duration._500, ScaledUtility)
# Test with numeric values
assert str (duration(0 )) == "duration-0"
assert str (duration(75 )) == "duration-75"
assert str (duration(150 )) == "duration-150"
assert str (duration(1000 )) == "duration-1000"
# Test arbitrary values
assert str (duration("250" )) == "duration-[250]"
assert str (duration("2s" )) == "duration-[2s]"
assert str (duration("100ms" )) == "duration-[100ms]"
assert str (duration("0.5s" )) == "duration-[0.5s]"
# Test custom properties
assert str (duration("--my-duration" )) == "duration-(--my-duration)"
assert str (duration("--animation-speed" )) == "duration-(--animation-speed)"
# Run the tests
test_transitions_and_animation_duration_examples()
Transition Timing Function
Control the easing of CSS transitions:
EaseFactory
def EaseFactory(
values_dict:Optional= None , # Dictionary mapping attribute names to CSS values
doc:Optional= None , # Optional documentation string
):
Factory for easing/timing function utilities with custom value support.
test_transitions_and_animation_timing_examples
def test_transitions_and_animation_timing_examples(
):
Test transition timing function utilities.
Exported source
# Create ease factory
ease = EaseFactory(
{
"linear" : "ease-linear" ,
"_in" : "ease-in" ,
"out" : "ease-out" ,
"in-out" : "ease-in-out" ,
"initial" : "ease-initial"
},
"Transition timing function utilities for controlling the easing of CSS transitions"
) # The ease factory
Exported source
def test_transitions_and_animation_timing_examples():
"""Test transition timing function utilities."""
# Test predefined easing functions
assert str (ease.linear) == "ease-linear"
assert str (ease._in) == "ease-in" # Note: 'in' is a Python keyword, so we use 'in_'
assert str (ease.out) == "ease-out"
assert str (ease.in_out) == "ease-in-out"
assert str (ease.initial) == "ease-initial"
# Test custom properties
assert ease("--my-ease" ) == "ease-(--my-ease)"
assert ease("--custom-timing" ) == "ease-(--custom-timing)"
# Test cubic-bezier functions
assert ease("cubic-bezier(0.4, 0, 0.2, 1)" ) == "ease-[cubic-bezier(0.4, 0, 0.2, 1)]"
assert ease("cubic-bezier(0.1, 0.7, 1.0, 0.1)" ) == "ease-[cubic-bezier(0.1, 0.7, 1.0, 0.1)]"
# Test steps function
assert ease("steps(4, jump-start)" ) == "ease-[steps(4, jump-start)]"
# Run the tests
test_transitions_and_animation_timing_examples()
Transition Delay
Control the delay of CSS transitions:
DelayFactory
def DelayFactory(
prefix:str , config:ScaleConfig, doc:Optional= None
):
Factory for delay utilities with millisecond support.
Exported source
# Standard delay values in milliseconds (same as duration scale)
DELAY_SCALE = [0 , 75 , 100 , 150 , 200 , 300 , 500 , 700 , 1000 ] # Standard Tailwind delay scale
Exported source
DELAY_CONFIG = ScaleConfig( # Delay configuration
numeric= False , # Don't use full numeric scale
decimals= False ,
fractions= False ,
named= None ,
special= {
"0" : "0" ,
"75" : "75" ,
"100" : "100" ,
"150" : "150" ,
"200" : "200" ,
"300" : "300" ,
"500" : "500" ,
"700" : "700" ,
"1000" : "1000"
},
negative= False
)
test_transitions_and_animation_delay_examples
def test_transitions_and_animation_delay_examples(
):
Test transition delay utilities.
Exported source
# Create delay factory
delay = DelayFactory("delay" , DELAY_CONFIG, "Transition delay utilities for controlling the delay of CSS transitions" ) # The delay factory
Exported source
def test_transitions_and_animation_delay_examples():
"""Test transition delay utilities."""
# Test standard delay values with attributes
assert str (delay._0) == "delay-0"
assert str (delay._75) == "delay-75"
assert str (delay._100) == "delay-100"
assert str (delay._150) == "delay-150"
assert str (delay._200) == "delay-200"
assert str (delay._300) == "delay-300"
assert str (delay._500) == "delay-500"
assert str (delay._700) == "delay-700"
assert str (delay._1000) == "delay-1000"
# Test all attributes are available for autocomplete
assert hasattr (delay, '_0' )
assert hasattr (delay, '_75' )
assert hasattr (delay, '_100' )
assert hasattr (delay, '_150' )
assert hasattr (delay, '_200' )
assert hasattr (delay, '_300' )
assert hasattr (delay, '_500' )
assert hasattr (delay, '_700' )
assert hasattr (delay, '_1000' )
# Verify they are ScaledUtility instances
assert isinstance (delay._300, ScaledUtility)
assert isinstance (delay._500, ScaledUtility)
# Test with numeric values
assert str (delay(0 )) == "delay-0"
assert str (delay(75 )) == "delay-75"
assert str (delay(150 )) == "delay-150"
assert str (delay(1000 )) == "delay-1000"
# Test arbitrary values
assert str (delay("250" )) == "delay-[250]"
assert str (delay("2s" )) == "delay-[2s]"
assert str (delay("100ms" )) == "delay-[100ms]"
assert str (delay("0.5s" )) == "delay-[0.5s]"
# Test custom properties
assert str (delay("--my-delay" )) == "delay-(--my-delay)"
assert str (delay("--animation-delay" )) == "delay-(--animation-delay)"
# Run the tests
test_transitions_and_animation_delay_examples()
Animation
Utilities for animating elements with CSS animations:
AnimationFactory
def AnimationFactory(
values_dict:Optional= None , # Dictionary mapping attribute names to CSS values
doc:Optional= None , # Optional documentation string
):
Factory for animation utilities with custom value support.
test_transitions_and_animation_examples
def test_transitions_and_animation_examples(
):
Test animation utilities.
Exported source
# Create animation factory
animate = AnimationFactory(
{
"spin" : "animate-spin" ,
"ping" : "animate-ping" ,
"pulse" : "animate-pulse" ,
"bounce" : "animate-bounce" ,
"none" : "animate-none"
},
"Animation utilities for animating elements with CSS animations"
) # The animation factory
Exported source
def test_transitions_and_animation_examples():
"""Test animation utilities."""
# Test predefined animations
assert str (animate.spin) == "animate-spin"
assert str (animate.ping) == "animate-ping"
assert str (animate.pulse) == "animate-pulse"
assert str (animate.bounce) == "animate-bounce"
assert str (animate.none) == "animate-none"
# Test custom properties
assert animate("--my-animation" ) == "animate-(--my-animation)"
assert animate("--custom-spin" ) == "animate-(--custom-spin)"
# Test arbitrary animation values
assert animate("slide 1s ease-in-out" ) == "animate-[slide 1s ease-in-out]"
assert animate("fade 0.5s linear infinite" ) == "animate-[fade 0.5s linear infinite]"
assert animate("wiggle 1s ease-in-out infinite" ) == "animate-[wiggle 1s ease-in-out infinite]"
# Run the tests
test_transitions_and_animation_examples()
Practical Examples
Let’s see how to use these transition and animation utilities in real FastHTML components:
test_transitions_and_animation_fasthtml_examples
def test_transitions_and_animation_fasthtml_examples(
):
Test transition and animation utilities in practical FastHTML component examples.
Exported source
def test_transitions_and_animation_fasthtml_examples():
"""Test transition and animation utilities in practical FastHTML component examples."""
from fasthtml.common import Div, Button, Span, A, Img
from cjm_fasthtml_tailwind.utilities.backgrounds import bg
from cjm_fasthtml_tailwind.utilities.typography import font_size, text_color
from cjm_fasthtml_tailwind.utilities.spacing import p
from cjm_fasthtml_tailwind.utilities.borders import rounded
from cjm_fasthtml_tailwind.utilities.effects import shadow
from cjm_fasthtml_tailwind.utilities.transforms import scale_tw, translate
from cjm_fasthtml_tailwind.utilities.effects import opacity
from cjm_fasthtml_tailwind.utilities.transforms import transform
from cjm_fasthtml_tailwind.utilities.layout import display_tw
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import gap, grid_display
# Button with hover transition
button = Button(
"Hover me" ,
cls= combine_classes(
bg.blue._500, bg.blue._700.hover, text_color.white, p.x(4 ), p.y(2 ), rounded.full,
transition.colors,
duration._300,
ease.in_out
)
)
assert "transition-colors" in button.attrs['class' ]
assert "duration-300" in button.attrs['class' ]
assert "ease-in-out" in button.attrs['class' ]
# Card with shadow transition
card = Div(
"Content" ,
cls= combine_classes(
shadow.md, shadow.xl.hover,
transition.shadow,
duration._200
)
)
assert "transition-shadow" in card.attrs['class' ]
assert "duration-200" in card.attrs['class' ]
# Scale transform on hover
scale_div = Div(
"Scale on hover" ,
cls= combine_classes(
scale_tw(110 ).hover,
transition.transform,
duration._150,
ease.out
)
)
assert "transition-transform" in scale_div.attrs['class' ]
assert "duration-150" in scale_div.attrs['class' ]
assert "ease-out" in scale_div.attrs['class' ]
# Delayed transition
delayed_link = A(
"Delayed hover" ,
cls= combine_classes(
text_color.gray._600, text_color.blue._500.hover,
transition.colors,
duration._500,
delay._200
)
)
assert "delay-200" in delayed_link.attrs['class' ]
# Multiple property transitions
multi_transition = Div(
"Multiple transitions" ,
cls= combine_classes(
opacity._50, opacity._100.hover, transform.gpu, translate.y(1 ).hover,
transition("opacity, transform" ),
duration._300
)
)
assert "transition-[opacity, transform]" in multi_transition.attrs['class' ]
# Return all examples in a grid layout
return Div(
button,
card,
scale_div,
delayed_link,
multi_transition,
cls= combine_classes(grid_display, gap(5 ))
)
# Run the tests
test_transitions_and_animation_fasthtml_examples()
test_func = test_transitions_and_animation_fasthtml_examples
app, rt = create_test_app()
@rt
def index():
return create_test_page(test_func.__doc__.title().replace('.' , '' ), test_func())
server = start_test_server(app)
display(HTMX())
server.stop()
test_transitions_and_animation_animation_fasthtml_examples
def test_transitions_and_animation_animation_fasthtml_examples(
):
Test animation utilities in practical FastHTML component examples.
Exported source
def test_transitions_and_animation_animation_fasthtml_examples():
"""Test animation utilities in practical FastHTML component examples."""
from fasthtml.common import Div, Span, Button
from cjm_fasthtml_tailwind.utilities.borders import border, border_color, rounded
from cjm_fasthtml_tailwind.utilities.sizing import w, h
from cjm_fasthtml_tailwind.utilities.backgrounds import bg
from cjm_fasthtml_tailwind.utilities.layout import position, top, right, display_tw
from cjm_fasthtml_tailwind.utilities.typography import font_size, text_color
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import gap, grid_display
grid_display
# Loading spinner
spinner = Div(
cls= combine_classes(
border._2, border_color.gray._200, border_color.t.blue._500, rounded.full, w(6 ), h(6 ),
animate.spin
)
)
assert "animate-spin" in spinner.attrs['class' ]
# Ping notification
notification_dot = Span(
cls= combine_classes(
position.absolute, top.negative(1 ), right.negative(1 ), h(3 ), w(3 ), bg.red._500, rounded.full,
animate.ping
)
)
assert "animate-ping" in notification_dot.attrs['class' ]
# Pulse skeleton loader
skeleton = Div(
cls= combine_classes(
h(4 ), bg.gray._200, rounded.full,
animate.pulse
)
)
assert "animate-pulse" in skeleton.attrs['class' ]
# Bounce arrow
arrow = Div(
"↓" ,
cls= combine_classes(
font_size._2xl,
animate.bounce
)
)
assert "animate-bounce" in arrow.attrs['class' ]
# Custom animation
custom_animated = Div(
"Custom animation" ,
cls= combine_classes(
animate("slide-in 0.5s ease-out forwards" )
)
)
assert "animate-[slide-in 0.5s ease-out forwards]" in custom_animated.attrs['class' ]
# Animation with CSS variable
var_animated = Div(
"Variable animation" ,
cls= combine_classes(
animate("--custom-fade-in" )
)
)
assert "animate-(--custom-fade-in)" in var_animated.attrs['class' ]
# Return all examples in a grid layout
return Div(
spinner,
notification_dot,
skeleton,
arrow,
custom_animated,
var_animated,
cls= combine_classes(grid_display, gap(5 ))
)
# Run the tests
test_transitions_and_animation_animation_fasthtml_examples()
↓
Custom animation
Variable animation
test_func = test_transitions_and_animation_animation_fasthtml_examples
app, rt = create_test_app()
@rt
def index():
return create_test_page(test_func.__doc__.title().replace('.' , '' ), test_func())
server = start_test_server(app)
display(HTMX())
server.stop()
test_transitions_and_animation_composition_fasthtml_examples
def test_transitions_and_animation_composition_fasthtml_examples(
):
Test composing multiple transition utilities together.
Exported source
def test_transitions_and_animation_composition_fasthtml_examples():
"""Test composing multiple transition utilities together."""
from fasthtml.common import Div, Button
from cjm_fasthtml_tailwind.utilities.backgrounds import bg_linear, from_color, to_color
from cjm_fasthtml_tailwind.utilities.transforms import scale_tw, translate, transform
from cjm_fasthtml_tailwind.utilities.effects import shadow, opacity
from cjm_fasthtml_tailwind.utilities.layout import display_tw
from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import gap, grid_display
# Complete transition setup
interactive_element = Button(
"Interactive" ,
cls= combine_classes(
bg_linear.to_r, from_color.blue._500, to_color.purple._600,
from_color.blue._600.hover, to_color.purple._700.hover,
transform.gpu, scale_tw(105 ).hover, scale_tw(95 ).active,
shadow.lg, shadow.xl.hover,
transition.all , # Transition all properties
duration._300,
ease.in_out,
delay._0
)
)
assert "transition-all" in interactive_element.attrs['class' ]
assert "duration-300" in interactive_element.attrs['class' ]
assert "ease-in-out" in interactive_element.attrs['class' ]
assert "delay-0" in interactive_element.attrs['class' ]
# Different transitions for different properties
multi_property = Div(
"Multi-property transitions" ,
cls= combine_classes(
opacity._75, opacity._100.hover,
transform.gpu, translate.x(2 ).hover,
transition("opacity, transform" ),
duration("200ms" ), # Custom duration
ease("cubic-bezier(0.4, 0, 0.2, 1)" ) # Custom easing
)
)
assert "transition-[opacity, transform]" in multi_property.attrs['class' ]
assert "duration-[200ms]" in multi_property.attrs['class' ]
assert "ease-[cubic-bezier(0.4, 0, 0.2, 1)]" in multi_property.attrs['class' ]
# Combining animation with transitions
animated_transitional = Div(
"Loading..." ,
cls= combine_classes(
animate.pulse,
opacity._50.hover,
transition.opacity,
duration._150
)
)
assert "animate-pulse" in animated_transitional.attrs['class' ]
assert "transition-opacity" in animated_transitional.attrs['class' ]
# Return all examples in a grid layout
return Div(
interactive_element,
multi_property,
animated_transitional,
cls= combine_classes(grid_display, gap(5 ))
)
# Run the tests
test_transitions_and_animation_composition_fasthtml_examples()
Interactive Multi-property transitions
Loading...
test_func = test_transitions_and_animation_composition_fasthtml_examples
app, rt = create_test_app()
@rt
def index():
return create_test_page(test_func.__doc__.title().replace('.' , '' ), test_func())
server = start_test_server(app)
display(HTMX())
server.stop()
Helper Functions
Convenient functions for common transition and animation patterns:
smooth_transition
def smooth_transition(
properties:str = 'all' , # Which properties to transition (default: all)
duration_ms:int = 300 , # Duration in milliseconds
easing:str = 'in-out' , # Easing function
)-> str : # Combined CSS classes for smooth transitions
Create a smooth transition with common defaults.
hover_effect
def hover_effect(
duration_ms:int = 200 , # Duration in milliseconds
)-> str : # Combined CSS classes for hover effects
Standard hover effect transition for interactive elements.
fade_in
def fade_in(
duration_ms:int = 500 , # Duration in milliseconds
delay_ms:Optional= None , # Optional delay in milliseconds
)-> str : # Combined CSS classes for fade-in effect
Fade-in transition for entering elements.
loading_spinner
def loading_spinner(
)-> str : # Combined CSS classes for a loading spinner
Create a loading spinner animation.
skeleton_loader
def skeleton_loader(
)-> str : # Combined CSS classes for a skeleton loader
Create a skeleton loader animation for content placeholders.
test_transitions_and_animation_helper_examples
def test_transitions_and_animation_helper_examples(
):
Test helper functions for common transition patterns.
Exported source
def test_transitions_and_animation_helper_examples():
"""Test helper functions for common transition patterns."""
# Test smooth_transition
assert smooth_transition() == "transition-all duration-300 ease-in-out"
assert smooth_transition("colors" , 200 , "out" ) == "transition-colors duration-200 ease-out"
assert smooth_transition("opacity, transform" , 500 , "linear" ) == "transition-[opacity, transform] duration-500 ease-linear"
# Test hover_effect
assert hover_effect() == "transition-all duration-200 ease-in-out"
assert hover_effect(150 ) == "transition-all duration-150 ease-in-out"
# Test fade_in
assert fade_in() == "transition-opacity duration-500 ease-out"
assert fade_in(300 ) == "transition-opacity duration-300 ease-out"
assert fade_in(500 , 200 ) == "transition-opacity duration-500 ease-out delay-200"
# Test loading_spinner
assert loading_spinner() == "border-2 border-gray-200 border-t-current rounded-full animate-spin"
# Test skeleton_loader
assert skeleton_loader() == "bg-gray-200 animate-pulse"
# Run the tests
test_transitions_and_animation_helper_examples()