DEV Community

Simon Nyström
Simon Nyström

Posted on • Originally published at


Building a Progress Bar


This is part of the UI Kit with React, TypeScript, Storybook and Tailwind, make sure you've checked out the previous entries in the series if you find anything confusing 😊.

In this series I aim to implement a basic progress bar and integrate it with Storybook.

This will be a simple component compared to the ones we've made previously.

The finished product will look like this:


The ProgressBar

In the project, create two files:

  • src/components/ProgressBar/ProgressBar.tsx
  • src/stories/ProgressBar/ProgressBar.stories.tsx

This component is so simple that we can write it all in one go without really making any intermediate steps, so let's do that:

// ProgressBar.tsx

export type ProgressBarProps = {
  progress: number;
  progressText?: string;

const ProgressBar = ({ progress, progressText = "" }: ProgressBarProps) => {
  // Make sure our value stays between 0 and 100.
  const _progress = Math.min(Math.max(0, progress), 100);
  return (
    <div className="flex flex-col items-center justify-center">
      <div className="w-full border-2 border-indigo-700 h-6 rounded-md">
          className="bg-indigo-500 h-full transition-all duration-250"
          style={{ width: `${_progress}%` }}

export default ProgressBar;
Enter fullscreen mode Exit fullscreen mode

There is nothing fancy going on in this component, basically we have an outer-most div to let us place the optional progressText where we want it to. There is also a wrapper for the progress bar outline and then there is the progress bar div itself which scales its width based on the progress (from 0 to 100).

Adding the Stories

In the file we created earlier, src/stories/ProgressBar/ProgressBar.stories.tsx, place the following:

import { ComponentMeta, Story } from "@storybook/react";
import ProgressBar, {
} from "../../components/ProgressBar/ProgressBar";

export default {
  title: "Progress Bar",
  component: ProgressBar,
} as ComponentMeta<typeof ProgressBar>;

const Template: Story<ProgressBarProps> = (args) => (
  <div className="w-56">
    <ProgressBar {...args} />

export const WithLoadingText = Template.bind({});
WithLoadingText.args = {
  progressText: "Loading...",
  progress: 23,

export const WithoutLoadingText = Template.bind({});
WithoutLoadingText.args = {
  progress: 50,
Enter fullscreen mode Exit fullscreen mode

This is a lot simpler than our stories from previous entries in this series, and it's nice to do something simpler for a change. This is all we need and we will now have two predefined stories, one with text and one without.

Running Storybook

To see how this actually looks in reality, we'll need to start our Storybook by running yarn storybook.

Run Storybook, visit http://localhost:6006 and you'll find the ProgressBar component in the sidebar.


If you can't get it to run, or have some other concerns, check it out from my repo and see if that works:

Stay tuned for the next entry in the series 😊. What component would you like to see next?

Top comments (1)


11 Tips That Make You a Better Typescript Programmer

1 Think in {Set}

Type is an everyday concept to programmers, but it’s surprisingly difficult to define it succinctly. I find it helpful to use Set as a conceptual model instead.

#2 Understand declared type and narrowed type

One extremely powerful typescript feature is automatic type narrowing based on control flow. This means a variable has two types associated with it at any specific point of code location: a declaration type and a narrowed type.

#3 Use discriminated union instead of optional fields


Read the whole post now!