A drop-in numeric countdown block for OutSystems Reactive Web. Point it at a target date and time, and it displays a clean D / H / M / S countdown that ticks in real time. Pauses and resumes cleanly, fires an event when the target is reached, and cleans itself up on navigation. Pure client-side, no dependencies.
Countdown Timer shows the time remaining until a target moment as four styled number slots — Days, Hours, Minutes, Seconds — that update on a configurable interval. It's designed for the common cases where an app needs to show a live countdown: event launches, booking cutoffs, promo expirations, session-timeout displays, or any moment the user should be aware is approaching.
OnComplete
OnTick
.oap
CountdownTimer TargetDateTime = MyTargetDate IsRunning = True TickIntervalMs = 1000 Handle OnComplete: ShowMessage("Time's up!")
Drop the block on a screen, bind TargetDateTime to a variable set to your target moment, and handle OnComplete to react when it hits zero. Everything else is optional.
TargetDateTime
CountdownTimer
IsRunning
True
TickIntervalMs
1000
RemainingSeconds
Tick
CurrDateTime()
The countdown is computed from "now vs. target," not from an internal accumulator. That means pause-then-resume-later doesn't shift the target — when you resume, the display reflects however much time is now actually left until the target.
This is the correct behavior for "countdown to a specific moment" (a scheduled event, a booking cutoff). If your use case is instead "countdown of N seconds from when the user pressed Start," you'd need to reset TargetDateTime on resume rather than toggle IsRunning — that pattern is a couple of lines in the consumer's action.
The block ships with a clean numeric look — four styled number blocks in a row, with tabular-numeric alignment so digits don't jitter as they change. All styling is on the ct-slot, ct-num, and ct-label classes. Override in your app theme to rebrand:
ct-slot
ct-num
ct-label
.ct-slot { background: #eef2ff; border-radius: 16px; } .ct-num { color: #4338ca; font-size: 34px; } .ct-label { color: #6366f1; }
The block uses inline-flex, so it flows naturally next to other content and doesn't force a line of its own.
inline-flex
Countdown to a fixed target (event launch, promo end):
Screen variable: LaunchAt (Date Time) = whenever the launch is CountdownTimer: TargetDateTime = LaunchAt IsRunning = True Handle OnComplete: navigate to the launched screen
Countdown of N seconds from now (session warning, wait timer):
Screen action Start: TargetDate = AddSeconds(CurrDateTime(), 60) IsRunning = True CountdownTimer: TargetDateTime = TargetDate IsRunning = IsRunning
Driving another UI element from OnTick:
Handle OnTick(RemainingSeconds): ProgressPercent = 100 - (RemainingSeconds * 100.0 / TotalDurationSeconds) // bind ProgressPercent to a linear progress bar elsewhere on the screen
The display shows 0d 00:00:00 immediately.TargetDateTime is in the past. Set it to a future moment. If it's dynamically computed (e.g. AddSeconds(CurrDateTime(), X)), make sure that assignment runs before the block reads it.
AddSeconds(CurrDateTime(), X)
The display doesn't update after I change TargetDateTime.The block re-evaluates on parameter change, so this usually means the change isn't propagating. Confirm the block's TargetDateTime input is bound to a screen variable (not a static value), and that your action actually updates that variable.
Pause doesn't seem to freeze the countdown accurately.See section 7. The countdown is target-relative, not accumulator-based. Resuming shows the real time now left until the target, not "where it was" when paused.
Timers seem to be running in the background after I navigate away.The block clears its own interval on destroy. If you're seeing runaway ticks, confirm the block's On Destroy event is wired (it should call the built-in stop action). This is the single most important lifecycle step for anything using setInterval.
setInterval
Multiple countdowns on the same screen conflict.Version 1 uses a single global timer state, so multiple simultaneous instances on the same page can interfere. If you need this, keep the countdowns on separate screens for now — proper multi-instance support is a candidate for v2.
TickIntervalMs = 1000