Animated Delivery Order Button
A modern delivery order button with an animated truck, moving road effect and smooth order confirmation state.
<div class="cr-order-stage">
<button
class="cr-order-btn"
id="crOrderBtn"
type="button"
>
<span class="cr-order-text">
Place Order
</span>
<span
class="cr-delivery-scene"
aria-hidden="true"
>
<span class="cr-road">
<span></span>
<span></span>
<span></span>
</span>
<span class="cr-truck">
<span class="cr-truck-box">
<span class="cr-package-line"></span>
</span>
<span class="cr-truck-cab">
<span class="cr-window"></span>
</span>
<span
class="cr-wheel cr-wheel-one"
></span>
<span
class="cr-wheel cr-wheel-two"
></span>
</span>
</span>
<span
class="cr-order-success"
aria-hidden="true"
>
<span class="cr-check">
<svg viewBox="0 0 24 24">
<path
d="M5 12.5l4.2 4.2L19 7"
></path>
</svg>
</span>
<span class="cr-success-text">
Order Placed
</span>
</span>
</button>
</div>
.cr-order-stage {
min-height: 340px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
background:
radial-gradient(
circle at 50% 45%,
rgba(124, 58, 237, 0.16),
transparent 34%
),
#070d19;
}
.cr-order-btn {
position: relative;
width: 210px;
height: 64px;
padding: 0;
border: 1px solid rgba(103, 232, 249, 0.32);
border-radius: 18px;
background: linear-gradient(135deg, #111d31, #0b1221);
color: #ffffff;
font-family: Inter, system-ui, sans-serif;
cursor: pointer;
overflow: hidden;
}
.cr-order-text {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 17px;
font-weight: 700;
}
.cr-order-btn.cr-running .cr-order-text {
opacity: 0;
transform: translateY(-14px) scale(0.9);
}
.cr-delivery-scene {
position: absolute;
inset: 0;
opacity: 0;
pointer-events: none;
}
.cr-order-btn.cr-driving .cr-delivery-scene {
opacity: 1;
}
.cr-road {
position: absolute;
left: 18px;
right: 18px;
bottom: 12px;
height: 2px;
overflow: hidden;
background: rgba(103, 232, 249, 0.14);
}
.cr-road span {
position: absolute;
top: 0;
width: 24px;
height: 2px;
border-radius: 10px;
background: linear-gradient(90deg, transparent, #67e8f9);
}
.cr-road span:nth-child(1) {
left: 15px;
}
.cr-road span:nth-child(2) {
left: 75px;
}
.cr-road span:nth-child(3) {
left: 135px;
}
.cr-order-btn.cr-driving .cr-road span {
animation: cr-road-move 0.65s linear infinite;
}
@keyframes cr-road-move {
from {
transform: translateX(45px);
}
to {
transform: translateX(-65px);
}
}
.cr-truck {
position: absolute;
left: -82px;
top: 17px;
width: 72px;
height: 38px;
}
.cr-order-btn.cr-driving .cr-truck {
animation:
cr-truck-drive 2.15s
cubic-bezier(.45, 0, .3, 1)
forwards;
}
@keyframes cr-truck-drive {
0% {
transform: translateX(0);
}
18% {
transform: translateX(90px);
}
67% {
transform: translateX(125px);
}
100% {
transform: translateX(310px);
}
}
.cr-truck-box {
position: absolute;
left: 0;
top: 3px;
width: 43px;
height: 27px;
border: 1px solid rgba(103, 232, 249, 0.75);
border-radius: 5px 4px 3px 5px;
background: linear-gradient(135deg, #172742, #101a2e);
}
.cr-package-line {
position: absolute;
left: 7px;
top: 8px;
width: 18px;
height: 10px;
border: 1px solid rgba(139, 92, 246, 0.75);
border-radius: 2px;
}
.cr-truck-cab {
position: absolute;
left: 42px;
top: 10px;
width: 27px;
height: 20px;
border: 1px solid rgba(103, 232, 249, 0.75);
border-radius: 3px 8px 4px 2px;
background: linear-gradient(135deg, #15263f, #0d1728);
}
.cr-window {
position: absolute;
top: 3px;
right: 4px;
width: 10px;
height: 7px;
border-radius: 2px 5px 2px 2px;
background: linear-gradient(135deg, #67e8f9, #8b5cf6);
}
.cr-wheel {
position: absolute;
bottom: 1px;
width: 11px;
height: 11px;
border: 2px solid #67e8f9;
border-radius: 50%;
background: #070d19;
}
.cr-wheel-one {
left: 11px;
}
.cr-wheel-two {
right: 7px;
}
.cr-order-success {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 9px;
opacity: 0;
}
.cr-order-btn.cr-success .cr-order-success {
opacity: 1;
}
.cr-check {
width: 25px;
height: 25px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid rgba(103, 232, 249, 0.65);
border-radius: 50%;
color: #67e8f9;
}
.cr-check svg {
width: 15px;
height: 15px;
fill: none;
stroke: currentColor;
stroke-width: 2.5;
stroke-linecap: round;
stroke-linejoin: round;
}
.cr-success-text {
font-size: 15px;
font-weight: 700;
}
(function () {
var button =
document.getElementById(
'crOrderBtn'
);
if (!button) {
return;
}
var running = false;
button.addEventListener(
'click',
function () {
if (running) {
return;
}
if (
button.classList.contains(
'cr-success'
)
) {
button.classList.remove(
'cr-success'
);
button.classList.remove(
'cr-running'
);
return;
}
running = true;
button.classList.add(
'cr-running'
);
setTimeout(
function () {
button.classList.add(
'cr-driving'
);
},
280
);
setTimeout(
function () {
button.classList.remove(
'cr-driving'
);
button.classList.add(
'cr-success'
);
},
2600
);
setTimeout(
function () {
running = false;
},
3150
);
}
);
})();
How This Animated Delivery Order Button Works
The Animated Delivery Order Button turns a normal “Place Order” action into a short delivery sequence. The HTML keeps everything inside a single .cr-order-btn button. It contains three main visual states: the initial order text, a delivery scene with a truck and road, and a success state containing an SVG checkmark with the “Order Placed” message.
The button itself is 210px wide and 64px high with an 18px border radius. Its dark blue gradient background is paired with a subtle cyan border. The surrounding .cr-order-stage uses flexbox to center the button and adds a radial purple glow over a #070d19 background.
The delivery truck is built entirely from nested HTML elements and CSS rather than an image. Separate elements form the cargo box, package marking, cab, window, and two circular wheels. The truck starts at left: -82px, placing it outside the visible button area. Because the button uses overflow: hidden, the truck only becomes visible as it drives through the button.
JavaScript controls the sequence by adding and removing CSS classes. On the first click, cr-running hides the original text. After a 280ms delay, JavaScript adds cr-driving, which reveals the delivery scene and starts the truck and road animations. The truck uses the cr-truck-drive keyframe animation for 2.15 seconds with a custom cubic-bezier timing function.
While the truck moves, the three road segments repeatedly travel from right to left using the cr-road-move animation. Each cycle takes 0.65 seconds. This opposite movement helps create the impression that the truck is travelling forward even though the animation takes place inside a small button.
At 2600ms, JavaScript removes the driving state and adds cr-success. The delivery scene disappears and the checkmark with “Order Placed” becomes visible. A running variable prevents additional clicks while the sequence is active. After 3150ms, the lock is released. Clicking the successful button again removes the success and running classes, returning it to its initial state. For more information about this animation technique, see the MDN CSS animations documentation.
Customizing the Animated Delivery Order Button
Most of the appearance and timing can be adjusted through the existing CSS values, while the JavaScript delays control when each state begins and ends.
- Change the button
width: 210pxandheight: 64pxto adjust its overall size. - Modify the
18pxborder radius for sharper or more rounded corners. - Replace the
#111d31and#0b1221colors to create a different button background. - Change
#67e8f9and#8b5cf6to customize the cyan and purple accents used across the truck, window, road, and checkmark. - Adjust the
2.15scr-truck-driveduration to control how quickly the truck crosses the button. - Change the road animation’s
0.65sduration to make the passing road marks move faster or slower. - Adjust the JavaScript delays of
280,2600, and3150milliseconds to change the timing between the initial, driving, success, and unlocked states.
Where to Use This Animated Delivery Order Button
This component works best when an order-related action benefits from immediate visual feedback without requiring a large loading interface.
- E-commerce checkout and order confirmation screens.
- Food delivery ordering interfaces.
- Grocery and local delivery applications.
- Shipping or courier service forms.
- Demo storefronts and interactive product prototypes.
- Cart interfaces where users need clear feedback after submitting an order.
The animation represents delivery directly, so it is most natural for commerce and shipping interfaces. For an alternative button that communicates an operation in progress without the delivery theme, the Loading Button is a related CodeRipple component worth considering.
Frequently Asked Questions
Does the Animated Delivery Order Button require JavaScript?
Yes. JavaScript listens for the button click and controls the cr-running, cr-driving, and cr-success classes. It also uses setTimeout() calls to coordinate the different stages of the animation.
Is the delivery truck an image or SVG?
The truck is constructed from HTML elements styled with CSS. The cargo box, cab, window, package marking, and wheels are separate elements. Only the success checkmark uses an inline SVG.
What prevents users from restarting the animation while the truck is moving?
The script uses a running Boolean variable. It becomes true when the sequence starts, and additional clicks immediately return while that value remains true. It changes back to false after 3150ms.
Can the button return to the Place Order state after showing Order Placed?
Yes. Once the animation has finished and the button can receive clicks again, clicking the success state removes both cr-success and cr-running. This reveals the original “Place Order” text and prepares the button for another sequence.
The Animated Delivery Order Button combines CSS keyframes with simple JavaScript class changes to provide clear visual feedback for an order action while keeping the entire interaction inside one compact button.
