Library / SDK
Eugnis/react-native-timeline-flatlist avatar
Eugnis/react-native-timeline-flatlist

react-native-timeline-flatlist: a timeline component built on FlatList

FlatList based timeline component for React Native for iOS and Android

521 stars73 forksTypeScriptMIT

At a glance

What is it?
This package gives you a vertical timeline for React Native, with the line, the circle marker, the time label and the description all styled from props, and TypeScript types bundled in. It is small, it is MIT licensed, and it has a single tagged release, which tells you something about how much maintenance to expect.
Who is it for?
Adopt react-native-timeline-flatlist if you need a vertical timeline in a React Native app and want the FlatList performance model rather than a scroll view with mapped children.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 97 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the component is, and how much of it there is

This is a FlatList based timeline component for React Native, for iOS and Android, and the package is published to npm as react-native-timeline-flatlist.

The important word in that description is FlatList. A timeline is a list, and the naive way to build one in React Native is to map over your data inside a ScrollView, which renders every row whether or not it is on screen. Building on FlatList means the rows are virtualised, so a timeline of a thousand events costs roughly what a timeline of ten events costs in memory.

That matters more for a timeline than for most lists, because the whole point of a timeline is usually to show a long history. The data shape is a plain array, and each entry carries a time, a title and a description:

jsx
import Timeline from 'react-native-timeline-flatlist'

const data = [
  {time: '09:00', title: 'Event 1', description: 'Event 1 Description'},
  {time: '10:45', title: 'Event 2', description: 'Event 2 Description'},
  {time: '12:00', title: 'Event 3', description: 'Event 3 Description'},
  {time: '14:00', title: 'Event 4', description: 'Event 4 Description'},
  {time: '16:30', title: 'Event 5', description: 'Event 5 Description'}
]

export default function BasicExample() {
  return <Timeline data={data} />
}

That is the whole basic usage. The component takes the data and renders the timeline, with the vertical line, the circle marker on each row, the time label and the title and description beside it.

The package is MIT licensed, the primary language is TypeScript, and the recent releases list a single version, v1.0.1, dated 2026-07-18, with the last push the same day. The topic list names android, cross-platform, flatlist, ios, react-native and timeline.

The npm page is the homepage, and there is an Expo Snack demo linked from the README, which is the fastest way to see the component running without setting anything up.

TypeScript support, and the type import that shows the shape of the data

The library is written in TypeScript and the type definitions are bundled with the package, so no separate @types package is needed. The README is explicit that there is no @types/react-native-timeline-flatlist to install, which is the right arrangement for a package written in TypeScript in the first place.

The types are exported directly from the package, and the example is short enough to be the clearest statement of the data contract:

tsx
import Timeline, { TimelineProps, Data } from 'react-native-timeline-flatlist'

const data: Data[] = [
  { time: '09:00', title: 'Event 1', description: 'Event 1 Description' },
]

So the default export is the component, and two named types come with it: TimelineProps for the component's props and Data for the shape of a single row. The Data type has time, title and description as the fields the basic usage uses, and the wider examples show that more fields exist per row.

The package.json confirms the packaging arrangement. The main entry point is lib/index.js and the types entry is lib/index.d.ts, so the published package is the compiled TypeScript output rather than the source, and the files array includes both lib and src. The build script is tsc and prepublishOnly runs npm run build, so the type declarations are always regenerated from the current source before a publish rather than being committed and possibly stale.

Testing is done with Jest, and the package.json scripts cover the usual ground: the test script runs jest, there is a watch variant and a coverage variant, and the dev dependencies include @testing-library/react-native, react-test-renderer and babel-jest, which is the standard setup for testing a React Native component that renders host views.

The styling props, and the example that shows most of them at once

The customisation surface is a set of props, and the custom example is the one to read because it exercises most of them together.

jsx
export default function CustomExample() {
  return (
    <Timeline
      //..other props
      circleSize={20}
      circleColor='rgb(45,156,219)'
      lineColor='rgb(45,156,219)'
      timeContainerStyle={{minWidth: 52, marginTop: -5}}
      timeStyle={{textAlign: 'center', backgroundColor: '#ff9797', color: 'white', padding: 5, borderRadius: 13}}
      descriptionStyle={{color: 'gray'}}
      options={{
        style: {paddingTop: 5}
      }}
      isUsingFlatlist={true}
    />
  )
}

The visual props are circleSize, circleColor and lineColor, so the marker and the connecting line are independently controllable. The text props are named after the thing they style: timeContainerStyle for the box around the time label, timeStyle for the label text itself, and descriptionStyle for the description text. And options carries a style object for the container as a whole, which is where padding on the timeline itself goes.

The styles are plain React Native style objects, not a theme object, so they compose with whatever styling approach the host app already uses rather than imposing one.

The isUsingFlatlist prop deserves a note, because it is the one that looks optional but is the point of the package. It selects the FlatList implementation over the alternative, and the example sets it to true explicitly even in the customisation example, which suggests the author wants people to be deliberate about it rather than assuming the default.

That is consistent with the package name and with the fact that the component is described as FlatList based. The FlatList path is what gives you virtualised rows and the performance characteristics on long lists; the alternative exists for cases where the simpler implementation is preferable.

The marker variants: a dot, an icon, or your own element

The circle marker on each row is not fixed, and there are two documented ways to change it plus a third for anything else.

The first is the dot. The innerCircle prop takes the value 'dot' and the marker becomes a small filled circle rather than the default:

jsx
export default function CircleDotExample() {
  return (
    <Timeline
      //..other props
      innerCircle={'dot'}
    />
  )
}

The second is the icon, where innerCircle takes the value 'icon' and each row supplies its own image. The data entries carry the icon path and can also carry a lineColor per row, so a single timeline can have differently coloured lines:

jsx
const data = [
  {time: '09:00', title: 'Archery Training', description: 'The Beginner Archery and Beginner Crossbow course does not require you to bring any equipment, since everything you need will be provided for the course. ', lineColor: '#009688', icon: require('../img/archery.png')},
  {time: '10:45', title: 'Play Badminton', description: 'Badminton is a racquet sport played using racquets to hit a shuttlecock across a net.', icon: require('../img/badminton.png')},
  {time: '12:00', title: 'Lunch', icon: require('../img/lunch.png')},
  {time: '14:00', title: 'Watch Soccer', description: 'Team sport played between two teams of eleven players with a spherical ball. ', lineColor: '#009688', icon: require('../img/soccer.png')},
  {time: '16:30', title: 'Go to Fitness center', description: 'Look out for the Best Gym & Fitness Centers around me :)', icon: require('../img/dumbbell.png')}
]

The third is any React element, and this is the one that removes the limitation entirely. You can pass a React element as icon or as iconDefault, which means the marker is not restricted to an image source:

jsx
const data = [
  //...
  {time: '12:00', title: 'Custom rendered icon', icon: <Image
    style={{width: 20, height: 20}}
    source={{uri: 'https://reactnative.dev/img/tiny_logo.png'}}
  />},
  //...
]

The iconDefault prop is the counterpart to icon: it is the marker used for rows that do not specify their own, so you can set a default and override individual rows.

Note the shape of the icon data too. A row can have a time, a title, a description, an icon, a lineColor and an imageUrl, and several are optional. The Lunch row above has a time, a title and an icon and no description at all, and the layout copes with that.

Column format, rendering overrides, and the known problems

Two areas of the README are worth reading before you build on the component, because they are where the design decisions and the sharp edges are.

The first is the column format, and the table of contents marks it as being introduced in v0.2.0. There is a single column right option, a two column option, and a time container hiding option. The time container is the box around the time label, and the customisation example above sets timeContainerStyle with a minWidth and a marginTop, so the layout of that box is what determines whether the time sits neatly beside the marker or drifts. The hiding option is for the case where the time is not part of the information you need to show.

The second is the troubleshooting section, which has two entries and both are honest about the cause.

The shift problem is the first. A timeline draws a vertical line and a circle marker, and if the marker or the line is offset from the row it belongs to, the visual result is a broken timeline. The name of the section says the shift is a known issue rather than an accident of your setup.

The second entry is titled Timeline is rendered, but not displayed until scroll. That is the more interesting one, because it describes a case where the component is in the tree and the content is there, but you do not see it until you scroll. The usual cause of that class of problem in a FlatList is a measurement problem, where the initial layout has not happened when the rows are first laid out, and the fix is usually to make sure the container has a definite size or to force a re-render after the data has been measured.

The override render example is the other half of the customisation story. Beyond styling, you can replace how a row renders, and the data carries an imageUrl per row for a large header image alongside the icon, as in the override render example, whose entries combine time, title, description, lineColor, icon and imageUrl.

There is also a pull to refresh and load more example in the table of contents, which is the natural thing to want on a timeline that is fed by a server, and it is the reason the component is built on FlatList in the first place.

Editorial conclusion

Adopt react-native-timeline-flatlist if you need a vertical timeline in a React Native app and want the FlatList performance model rather than a scroll view with mapped children. Do not adopt it expecting an actively maintained component, because there is a single tagged release at v1.0.1 and the last push was in July 2026, and do check the troubleshooting notes in the README before you file a bug, since the shift problem and the render-but-not-visible-until-scroll issue are both known behaviours with documented causes. Before you start, read the column format section, because the single column right and two column layouts changed in v0.2.0 and the default may not be what you want.

Frequently asked questions

What does react-native-timeline-flatlist provide?

A FlatList based timeline component for React Native apps on iOS and Android, with a vertical line, a circle marker per row, a time label, a title and a description, and props for sizing, colours and text styles. The package is MIT licensed and published to npm as react-native-timeline-flatlist.

How do I install react-native-timeline-flatlist?

With npm install react-native-timeline-flatlist, or yarn add react-native-timeline-flatlist. The peer dependencies are react >= 17.0.0 and react-native >= 0.64.0, and there is an Expo Snack demo linked from the README to see it running.

Does react-native-timeline-flatlist need a separate @types package?

No. The library is written in TypeScript and ships its own type definitions, so there is no @types/react-native-timeline-flatlist to install. You can import the types directly, for example import Timeline, { TimelineProps, Data } from the package.

How do I change the circle marker in react-native-timeline-flatlist?

Set innerCircle to 'dot' for a plain filled marker or to 'icon' to use a per-row image, and you can also pass any React element as icon or iconDefault. The marker size and colour are controlled by circleSize and circleColor, and the connecting line by lineColor.

What known problems does the react-native-timeline-flatlist README document?

Two, under Troubleshooting: a shift problem where the marker or line is offset, and a case where the timeline is rendered but not displayed until you scroll. Both are documented in the README, so they are worth checking before you report a bug.

Official sources

  1. Eugnis/react-native-timeline-flatlist on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/eugnis-react-native-timeline-flatlist.svg)](https://hysenlabs.com/projects/eugnis-react-native-timeline-flatlist)

Was this useful?