Skip to content

A performant and flexible timer library for React Native, built with Reanimated for smooth animations and real-time timekeeping features like timer and stopwatch.

License

Notifications You must be signed in to change notification settings

amilmohd155/react-native-reanimated-timer

React Native Reanimated Timer

license runs with expo npm Reanimated v3 version

A Reanimated-powered library for creating smooth and customizable timers, stopwatches, and time displays in React Native. ⏳

React Native Reanimated Timer

Features

Features

  • 🧩 Highly Composable – All components — Timer, Stopwatch, and Clock — are fully composable for complete flexibility.
  • High Performance – Achieves smooth 60 FPS animations powered by Reanimated.
  • 🎨 Fully Customizable – Configure behavior, appearance, and animations through flexible props.
  • 🎞️ Built-in Entry & Exit Animations – Seamlessly integrate with Reanimated transitions.
  • 🧱 Powered by Reanimated – Built with Reanimated for smooth, performant, and reliable animations.
  • 🎨 Supports className Prop – Works with NativeWind for Tailwind-style styling, and optionally uses tailwind-merge for intelligent class merging.
  • 🚀 Expo-Compatible – Works out of the box with managed Expo projects.
  • TypeScript First – Fully typed for an enhanced developer experience and safer code.

Components

  • Timer – Countdown timer with customizable duration, animations, and callbacks. Check it out
  • Stopwatch – Accurate stopwatch with start, pause, and reset controls. Check it out
  • Digital Clock – Live clock display showing current time, updated in real-time. Check it out

Composability

All components — Timer, Stopwatch, and Clock — are now fully composable.

They share a common set of time unit segments: Day, Hour, Minute, Second, and Millisecond, AMPM.

This means you have full control over how time is displayed and animated. You can mix and match these building blocks to create custom layouts, animations, and styles that fit your app perfectly.

Example

import { Timer } from '@docren/react-native-reanimated-timer';

export default function App() {
  return (
    <Timer durationMs={60000}>
      <Timer.Minute />
      <Timer.Second />
      <Timer.Millisecond />
    </Timer>

    <Stopwatch autoStart>
      <Stopwatch.Hour />
      <Stopwatch.Minute />
      <Stopwatch.Second />
    </Stopwatch>

    <Clock format="12">
      <Clock.Hour />
      <Clock.Minute />
      <Clock.Second />
      <Clock.Millisecond />
      <Clock.AMPM />
    </Clock>
  );
}

Why Composability?

This design enables:

  • 🧱 Maximum Flexibility – Use only the units you need (Minute, Second, etc.).
  • 🎨 Full Customization – Add your own separators, labels, or styles between units.
  • ⚙️ Consistency – All unit components share a consistent API across Timer, Stopwatch, and Clock.
  • 🔄 Interchangeability – Swap components easily without changing the surrounding layout or logic.

Each component (Timer, Stopwatch, Clock) manages its own internal timing logic while exposing shared subcomponents for complete composability and freedom of use.

Learn more

Acknowledgements

  • 🙏 Component and Animation Inspiration
    This library is heavily inspired by react-native-animated-stopwatch-timer and the accompanying blog. It’s a great resource for understanding animation patterns with Reanimated—highly recommended!

  • 🧠 Custom Hook Design
    The internal time management logic is built on top of react-timer-hook, using it as a core dependency for reliable timekeeping. This allows leveraging its proven functionality while layering custom logic and controls tailored to the app’s specific needs.

    If you only need a headless timekeeping hook (without UI), you can use react-timer-hook directly.

Installation

npm install @docren/react-native-reanimated-timer

Note: This package is built on top of react-native-reanimated, so make sure it’s properly installed and configured in your project. Refer to the Reanimated installation guide if you haven’t already set it up.

Optional Peer Dependency

For better and more predictable class name merging, you can optionally install tailwind-merge >= 3.0.0:

npm install tailwind-merge

When twMerge={true}, the library uses tailwind-merge to intelligently combine class names. If tailwind-merge is not installed, it will gracefully fall back to the default behavior — the nearest className wins.

Usage

Check out this example Snack

Timer

Timer component that counts down from a specified duration.

Props

Prop Type Default Description
durationMs number - Required The duration in milliseconds for the timer.
intervalMs number 1000 The interval in milliseconds to update the timer.
autoStart boolean true Whether to start the timer automatically.
onExpire () => void undefined Callback function to be called when the timer expires.

For additional props, refer to the Common Props section.

Methods

start: () => void;

Starts the timer if it is not already running or paused.

timerRef.current?.start();

pause: () => void;

Pauses the timer if it is running.

timerRef.current?.pause();

resume: () => void;

Resumes the timer if it is paused.

timerRef.current?.resume();

restart: (duration: number; autoStart?: boolean) => void;

Restarts the timer with a new duration and optional autoStart value.

  • duration - The new duration in milliseconds.
  • autoStart - Whether to start the timer automatically. Optional, Defaults to true
timerRef.current?.restart(1800000, false); // Timer for 30 mins, with autoStart set to false

reset: () => void;

Resets the timer to the initial duration and intial autoStart value.

timerRef.current?.reset();

Stopwatch

Props

Prop Type Default Description
autoStart boolean false Whether to start the stopwatch automatically.
intervalMs number 1000 The interval in milliseconds to update the stopwatch.
offsetTimestamp Date undefined The offset timestamp to start the stopwatch from.

For additional props, refer to the Common Props section.

Methods

start: () => void;

Starts the stopwatch

timerRef.current?.start();

pause: () => void;

Pauses the stopwatch

timerRef.current?.pause();

reset: (autoStart?: boolean, offset?: Date) => void;

Resets the stopwatch with a new offset and autoStart value.

  • autoStart - Whether to start the timer automatically. Optional, Defaults to false
  • offset - The offset date to set the stopwatch to. Optional, Defaults to undefined
timerRef.current?.restart();

Clock

Clock component to display the current time.

  • It can be configured to show hours, minutes, seconds, and milliseconds.
  • The time format can be set to either 12-hour or 24-hour format.

Props

Prop Type Default Description
format '12' | '24' '24' The time format to be used.
intervalMs number 1000 The interval in milliseconds to update the clock.

For additional props, refer to the Common Props section.

Common Props

All common props are optional

Prop Type Default Description
animationDelay number 0 Delay before the animation starts (in milliseconds).
animationDuration number 80 Duration of the animation (in milliseconds).
animationDistance number 1200 Distance the animation moves.
animationDirection 'up' | 'down' 'down' Direction of the animation ('up' or 'down').
entering EntryOrExitLayoutType undefined Custom entering animation from react-native-reanimated.
exiting EntryOrExitLayoutType undefined Custom exiting animation from react-native-reanimated .
skipEntering boolean true Useful for preventing initial animation on mount.
skipExiting boolean false Useful for preventing exit animation on unmount.
twMerge boolean false Uses tailwind-merge to merge classNames.
style ViewStyle undefined Style for the component.
className string undefined Styling for component.
digitContainerStyle ViewStyle undefined Style for grouped digit's container. eg: [tens of seconds, units of seconds]
digitContainerClassName string undefined Styling for digit's container
digitStyle TextStyle undefined Style for the individual digits, eg: Tens of seconds
digitClassName string undefined Styling the individual digits

When twMerge={true}, the library uses tailwind-merge to intelligently combine class names. If tailwind-merge is not installed, it will gracefully fall back to the default behavior — the nearest className wins.

Segments

Each time unit is represented by an individual Segment component. These can be freely composed to control what parts of the time are displayed.

  • Day (not available for Clock)
  • Hour
  • Minute
  • Second
  • Millisecond
  • AM/PM (available only for Clock)
Prop Type Default Description
className string undefined Styles the segment container
style ViewStyle undefined Inline styles for the segment container
digitClassName string undefined Styles applied to the individual digits
digitStyle TextStyle undefined Inline styles for the individual digits

While each segment supports its own digitStyle and digitClassName, it’s generally recommended to define digitStyle at the root level. This ensures consistent styling across all segments for a unified look.

Related

Contributing

See the contributing guide to learn how to contribute to the repository and the development workflow.

License

This project is licensed under the MIT License.

MIT

Authors

Built with ❤️

About

A performant and flexible timer library for React Native, built with Reanimated for smooth animations and real-time timekeeping features like timer and stopwatch.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks