Custom Property
Animate any numeric CSS property with a unit. This is an escape hatch for CSS properties not covered by the first-class property modules.
Module: Anim.Property.Custom
GPU Accelerated: No — the only GPU-accelerated numeric property is opacity, which has its own first-class module .
Example
View Example
View Source Code
Transition Keyframe Sub WAAPI
module Animation.Transition.BorderRadius.Main exposing ( main )
import Anim.Builder exposing ( AnimBuilder )
import Anim.Engine.Transition as Transition
import Anim.Property.Custom as Property
import Anim.Unit exposing ( Unit (..) )
import Browser
import Html exposing ( Html , button , div , text )
import Html.Attributes exposing ( class , style )
import Html.Events exposing ( onClick )
import Motion.Easing as Easing exposing ( Easing (..) )
-- MAIN
main : Program () Model Msg
main =
Browser . element
{ init = \ _ -> init
, view = view
, update = update
, subscriptions = always Sub . none
}
-- MODEL
type alias Model =
{ animState : Transition . AnimState }
init : ( Model , Cmd Msg )
init =
( { animState =
Transition . init
[ Property . init animGroup ( Property . BorderRadius Px ) 0 ]
}
, Cmd . none
)
-- ANIMATION
animGroup : String
animGroup =
"radiusAnim"
standardTiming : Property . Builder { prop | withTiming : () } -> Property . Builder { prop | withTiming : () }
standardTiming =
Property . duration 800
>> Property . easing CubicInOut
roundCorners : AnimBuilder { eng | withTiming : () } -> AnimBuilder { eng | withTiming : () }
roundCorners =
Property . begin ( Property . BorderRadius Px )
>> Property . to 48
>> standardTiming
>> Property . end
squareCorners : AnimBuilder { eng | withTiming : () } -> AnimBuilder { eng | withTiming : () }
squareCorners =
Property . begin ( Property . BorderRadius Px )
>> Property . to 0
>> standardTiming
>> Property . end
-- UPDATE
type Msg
= TriggerRound
| TriggerSquare
update : Msg -> Model -> ( Model , Cmd Msg )
update msg model =
case msg of
TriggerRound ->
( { model
| animState =
Transition . animate model . animState <|
Transition . for animGroup
>> roundCorners
}
, Cmd . none
)
TriggerSquare ->
( { model
| animState =
Transition . animate model . animState <|
Transition . for animGroup
>> squareCorners
}
, Cmd . none
)
-- VIEW
view : Model -> Html Msg
view model =
div [ class "example-stage" ]
[ div [ class "example-controls" ]
[ button
[ onClick TriggerRound
, class "ui-action-button primary"
]
[ text "Round" ]
, button
[ onClick TriggerSquare
, class "ui-action-button primary"
]
[ text "Square" ]
]
, div
[ style "width" "100%"
, style "display" "flex"
, style "align-items" "center"
, style "justify-content" "center"
, style "padding-top" "10px"
]
[ div
( Transition . attributes animGroup model . animState
++ [ class "example-box"
, style "background-color" "#6366f1"
]
)
[]
]
]
module Animation.Keyframe.BorderRadius.Main exposing ( main )
import Anim.Builder exposing ( AnimBuilder )
import Anim.Engine.Keyframe as Keyframe
import Anim.Property.Custom as Property
import Anim.Unit exposing ( Unit (..) )
import Browser
import Html exposing ( Html , button , div , text )
import Html.Attributes exposing ( class , style )
import Html.Events exposing ( onClick )
import Motion.Easing as Easing exposing ( Easing (..) )
-- MAIN
main : Program () Model Msg
main =
Browser . element
{ init = \ _ -> init
, view = view
, update = update
, subscriptions = always Sub . none
}
-- MODEL
type alias Model =
{ animState : Keyframe . AnimState }
init : ( Model , Cmd Msg )
init =
( { animState =
Keyframe . init <|
[ Property . init animGroup ( Property . BorderRadius Px ) 0 ]
}
, Cmd . none
)
-- ANIMATION
animGroup : String
animGroup =
"boxAnim"
standardTiming : Property . Builder { prop | withTiming : () } -> Property . Builder { prop | withTiming : () }
standardTiming =
Property . duration 800
>> Property . easing CubicInOut
roundCorners : AnimBuilder { eng | withTiming : () } -> AnimBuilder { eng | withTiming : () }
roundCorners =
Property . begin ( Property . BorderRadius Px )
>> Property . to 48
>> standardTiming
>> Property . end
squareCorners : AnimBuilder { eng | withTiming : () } -> AnimBuilder { eng | withTiming : () }
squareCorners =
Property . begin ( Property . BorderRadius Px )
>> Property . to 0
>> standardTiming
>> Property . end
-- UPDATE
type Msg
= TriggerRound
| TriggerSquare
update : Msg -> Model -> ( Model , Cmd Msg )
update msg model =
case msg of
TriggerRound ->
( { model
| animState =
Keyframe . animate model . animState <|
Keyframe . for animGroup
>> roundCorners
}
, Cmd . none
)
TriggerSquare ->
( { model
| animState =
Keyframe . animate model . animState <|
Keyframe . for animGroup
>> squareCorners
}
, Cmd . none
)
-- VIEW
view : Model -> Html Msg
view model =
div
[ class "example-stage" ]
[ Keyframe . styleNode model . animState
, div [ class "example-controls" ]
[ button
[ onClick TriggerRound
, class "ui-action-button primary"
]
[ text "Round" ]
, button
[ onClick TriggerSquare
, class "ui-action-button primary"
]
[ text "Square" ]
]
, div
[ style "width" "100%"
, style "display" "flex"
, style "align-items" "center"
, style "justify-content" "center"
, style "padding-top" "10px"
]
[ div
( Keyframe . attributes animGroup model . animState
++ [ class "example-box"
, style "background-color" "#6366f1"
]
)
[]
]
]
module Animation.Sub.BorderRadius.Main exposing ( main )
import Anim.Builder exposing ( AnimBuilder )
import Anim.Engine.Sub as Sub
import Anim.Property.Custom as Property
import Anim.Unit exposing ( Unit (..) )
import Browser
import Html exposing ( Html , button , div , text )
import Html.Attributes exposing ( class , style )
import Html.Events exposing ( onClick )
import Motion.Easing as Easing exposing ( Easing (..) )
-- MAIN
main : Program () Model Msg
main =
Browser . element
{ init = \ _ -> init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Model =
{ animState : Sub . AnimState }
init : ( Model , Cmd Msg )
init =
( { animState =
Sub . init <|
[ Property . init animGroup ( Property . BorderRadius Px ) 0 ]
}
, Cmd . none
)
-- ANIMATION
animGroup : String
animGroup =
"radiusAnim"
standardTiming : Property . Builder { prop | withTiming : () } -> Property . Builder { prop | withTiming : () }
standardTiming =
Property . duration 800
>> Property . easing CubicInOut
roundCorners : AnimBuilder { eng | withTiming : () } -> AnimBuilder { eng | withTiming : () }
roundCorners =
Property . begin ( Property . BorderRadius Px )
>> Property . to 48
>> standardTiming
>> Property . end
squareCorners : AnimBuilder { eng | withTiming : () } -> AnimBuilder { eng | withTiming : () }
squareCorners =
Property . begin ( Property . BorderRadius Px )
>> Property . to 0
>> standardTiming
>> Property . end
-- UPDATE
type Msg
= GotSubMsg Sub . AnimMsg
| TriggerRound
| TriggerSquare
update : Msg -> Model -> ( Model , Cmd Msg )
update msg model =
case msg of
GotSubMsg subMsg ->
let
( newAnimState , _ ) =
Sub . update subMsg model . animState
in
( { model | animState = newAnimState }
, Cmd . none
)
TriggerRound ->
( { model
| animState =
Sub . animate model . animState <|
Sub . for animGroup
>> roundCorners
}
, Cmd . none
)
TriggerSquare ->
( { model
| animState =
Sub . animate model . animState <|
Sub . for animGroup
>> squareCorners
}
, Cmd . none
)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub . Sub Msg
subscriptions model =
Sub . subscriptions GotSubMsg model . animState
-- VIEW
view : Model -> Html Msg
view model =
div
[ class "example-stage" ]
[ div [ class "example-controls" ]
[ button
[ onClick TriggerRound
, class "ui-action-button primary"
]
[ text "Round" ]
, button
[ onClick TriggerSquare
, class "ui-action-button primary"
]
[ text "Square" ]
]
, div
[ style "width" "100%"
, style "display" "flex"
, style "align-items" "center"
, style "justify-content" "center"
, style "padding-top" "10px"
]
[ div
( Sub . attributes animGroup model . animState
++ [ class "example-box"
, style "background-color" "#6366f1"
]
)
[]
]
]
port module Animation . WAAPI . BorderRadius . Main exposing ( main )
import Anim.Builder exposing ( AnimBuilder )
import Anim.Engine.WAAPI as WAAPI
import Anim.Property.Custom as Property
import Anim.Unit exposing ( Unit (..) )
import Browser
import Html exposing ( Html , button , div , text )
import Html.Attributes exposing ( class , style )
import Html.Events exposing ( onClick )
import Json.Encode as Encode
import Motion.Easing as Easing exposing ( Easing (..) )
-- PORTS
port motionCmd : Encode . Value -> Cmd msg
port motionMsg : ( Encode . Value -> msg ) -> Sub msg
-- MAIN
main : Program () Model Msg
main =
Browser . element
{ init = \ _ -> init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Model =
{ animState : WAAPI . AnimState Msg }
init : ( Model , Cmd Msg )
init =
( { animState =
WAAPI . init motionCmd motionMsg <|
[ Property . init animGroup ( Property . BorderRadius Px ) 0 ]
}
, Cmd . none
)
-- ANIMATION
animGroup : String
animGroup =
"radiusAnim"
standardTiming : Property . Builder { prop | withTiming : () } -> Property . Builder { prop | withTiming : () }
standardTiming =
Property . duration 800
>> Property . easing CubicInOut
roundCorners : AnimBuilder { eng | withTiming : () } -> AnimBuilder { eng | withTiming : () }
roundCorners =
Property . begin ( Property . BorderRadius Px )
>> Property . to 48
>> standardTiming
>> Property . end
squareCorners : AnimBuilder { eng | withTiming : () } -> AnimBuilder { eng | withTiming : () }
squareCorners =
Property . begin ( Property . BorderRadius Px )
>> Property . to 0
>> standardTiming
>> Property . end
-- UPDATE
type Msg
= GotWaapiMsg WAAPI . AnimMsg
| TriggerRound
| TriggerSquare
update : Msg -> Model -> ( Model , Cmd Msg )
update msg model =
case msg of
GotWaapiMsg waapiMsg ->
let
( newAnimState , _ ) =
WAAPI . update waapiMsg model . animState
in
( { model | animState = newAnimState }
, Cmd . none
)
TriggerRound ->
let
( newAnimState , cmd ) =
WAAPI . animate model . animState <|
WAAPI . for animGroup
>> roundCorners
in
( { model | animState = newAnimState }
, cmd
)
TriggerSquare ->
let
( newAnimState , cmd ) =
WAAPI . animate model . animState <|
WAAPI . for animGroup
>> squareCorners
in
( { model | animState = newAnimState }
, cmd
)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
WAAPI . subscriptions GotWaapiMsg model . animState
-- VIEW
view : Model -> Html Msg
view model =
div
[ class "example-stage" ]
[ div [ class "example-controls" ]
[ button
[ onClick TriggerRound
, class "ui-action-button primary"
]
[ text "Round" ]
, button
[ onClick TriggerSquare
, class "ui-action-button primary"
]
[ text "Square" ]
]
, div
[ style "width" "100%"
, style "display" "flex"
, style "align-items" "center"
, style "justify-content" "center"
, style "padding-top" "10px"
]
[ div
( WAAPI . attributes animGroup model . animState
++ [ class "example-box"
, style "background-color" "#6366f1"
]
)
[]
]
]
Basic Usage
View Source Code
import Anim.Property.Custom as Property exposing ( Property (..) )
import Anim.Unit exposing ( Unit (..) )
borderRadiusAnimation : AnimBuilder eng -> AnimBuilder eng
borderRadiusAnimation =
Property . begin ( BorderRadius Px )
>> Property . to 24
>> Property . end
See the Properties Overview page for the shared usage patterns.
When to use Anim.Property.Custom
Use this module when Elm Motion doesn't provide a first-class module for the CSS property you need to animate. For color-based properties, use Anim.Property.CustomColor instead.
API
Types
Type
Description
Builder
Alias for the Internal builder used to configure the animation
AnimGroupName
Alias for the animation group name
Property
Typed property names
Initialization
Function
Signature
Description
init
AnimGroupName -> Property -> Float -> AnimBuilder eng -> AnimBuilder eng
Set the initial value — takes group name, CSS property (with unit embedded), and value
Build
Function
Signature
Description
begin
Property -> AnimBuilder eng -> Builder eng
Start building — takes CSS property (with unit embedded), using the currently selected animation group
end
Builder eng -> AnimBuilder eng
Finish building
Start Value
Function
Signature
Description
from
Float -> Builder eng -> Builder eng
Start value
End Value
Function
Signature
Description
to
Float -> Builder eng -> Builder eng
Absolute End value
by
Float -> Builder eng -> Builder eng
Relative End value
Timing
Function
Signature
Description
delay
Int -> Builder { eng | withTiming : () } -> Builder { eng | withTiming : () }
The delay in ms before the animation starts
duration
Int -> Builder { eng | withTiming : () } -> Builder { eng | withTiming : () }
The duration in ms that the animation lasts for
speed
Float -> Builder { eng | withTiming : () } -> Builder { eng | withTiming : () }
The rate of change per second
Easing
Function
Signature
Description
easing
Easing -> Builder eng -> Builder eng
Add natural motion
Spring
Function
Signature
Description
spring
Spring -> Builder { eng | withSpring : () } -> Builder { eng | withSpring : () }
Use spring physics instead of easing
Next Steps
The Custom Color Property.
Custom Color Property →