All Blogs
Blog

Create a React NPM Package with Vite and Storybook

Build and publish a simple React npm package using Vite and Storybook.

Last updated on April 24, 2026

Over the years, we have seen many tools, frameworks, and libraries built to improve the developer experience. Among these tools, we have Vite, which gained great popularity for its performance, customization, and seamless integration with libraries/frameworks like React, Vue, and Svelte.

In this tutorial, we will learn how to build and publish a simple React npm package using Vite and Storybook as our build and local development environment tools.

Project Setup

Let's start by creating a project folder called vite-react-npm-package. Inside, we will initialize our npm package with the command npm init -y, which will create a new file in our project folder called package.json and will contain the following code:

package.json
{
  "name": "vite-react-npm-package",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": ""
}

Let's go through a brief explanation of each field added in our new package.json file:

To complete the initial setup of our package.json file, we will add a new field called type:

package.json
{
  "name": "vite-react-npm-package",
  "version": "1.0.0",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": ""
}

type defines how our project should import modules. By setting the type field to the value module, we will enable ECMAScript modules in our package.

Dependencies

Now that we have completed the initial setup of our package.json file, we will explore two new fields: dependencies and devDependencies.

dependencies are the packages our project needs to work correctly. Each dependency follows the structure "package-name": package-version. To add a new dependency to our project, we need to run the command npm add package-name. This command will download all the new package files to our project (stored in a folder called node_modules) and automatically add the package to the dependencies field of our package.json file. Here is an example of the dependencies field:

package.json
{
  "name": "vite-react-npm-package",
  "version": "1.0.0",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "date-fns": "^4.1.0"
  }
}

devDependencies are almost identical to the dependencies field. The main difference is that dependencies are packages that our project needs to work (which will be bundled inside the production build of our package), while devDependencies are packages only required for development.

A good example would be the use of a linting package like eslint. This package is excellent for development since it analyzes our code and searches for problems, but our project does not need this package to work correctly; because of this, we can add it to our devDependencies field.

Here is an example of how the package.json file would look with the devDependencies field:

package.json
{
  "name": "vite-react-npm-package",
  "version": "1.0.0",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "devDependencies": {
    "eslint": "^9.13.0"
  }
}

Build the React Component

Now that we have completed the initial setup of our project, we will define our React component. For this, we will create a new folder inside our project called src, and inside, we will create a file called index.jsx where we will make a simple React component that increments/decrements a counter. Let's add to our index.jsx file the following code:

src/index.jsx
import React, { useState } from 'react';
 
export function Component() {
  const [count, setCount] = useState(0);
 
  return (
    <div>
      <p>Currently, the count is {count}</p>
      <button onClick={() => setCount(count - 1)}>Subtract</button>
      <button onClick={() => setCount(count + 1)}>Add</button>
    </div>
  );
}

To use the package in other projects, we need to run the command npm add vite-react-npm-package (remember to use your package's unique name). Once the package is installed, we should import and use it in the following way:

import { Component } from 'vite-react-npm-package';
 
export default function App () {
  return (
    <Component />
  );
}

Storybook Development Environment

Next, we will create our project's development environment. For this, we will use Storybook, a tool that creates a workshop for building our components.

Let's install Storybook in our project with the command npm add -D storybook @storybook/react-vite. Then, we will add the script "storybook": "storybook dev" to our package.json file, whose main purpose is to automatically set up and run the development environment.

Our package.json file should have the following code:

package.json
{
  "name": "vite-react-npm-package",
  "version": "1.0.0",
  "type": "module",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "storybook": "storybook dev"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "devDependencies": {
    "@storybook/react-vite": "^10.3.5",
    "storybook": "^10.3.5"
  }
}

Let's create our Storybook configuration file. We will create a new folder inside our project called .storybook, and inside, we will create a file called main.js, which defines the location of our project's stories and the framework used in our project. Let's add to our main.js file the following code:

.storybook/package.json
export default {
  stories: ['./*.stories.jsx'],
  framework: { name: '@storybook/react-vite' },
};

To complete our Storybook setup, we will create a story for our React component. A story is made by a default export (which describes the component) and named exports (which capture a specific state of the component).

For this, we will create a new file inside our .storybook folder called component.stories.jsx, and inside, we will add the following code:

.storybook/component.stories.jsx
import { Component } from '../src/index.jsx';
 
export default {
  title: 'Component',
  component: Component,
};
 
export const Example = {};

To start our development environment, we need to run the command npm run storybook. By default, a browser will open with the Storybook interface, where we can see our component and their states.

Vite Setup

Let's set up Vite as our project's build system. For this, we will install Vite as devDependencies with the command npm add -D vite. To configure our build process, we need to create a configuration file inside our project folder called vite.config.js, and inside, we will add the following code:

vite.config.js
import { resolve } from 'path';
import { defineConfig } from 'vite';
 
export default defineConfig({
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.jsx'),
      name: 'index',
      fileName: 'index',
    },
    rollupOptions: {
      external: ['react'],
      output: {
        globals: {
          react: 'React',
        },
      },
    },
  },
})

Here is a brief explanation of each element added in our new vite.config.js file:

Now, we will update our package.json file with four new changes:

Our package.json file should now have the following code:

package.json
{
  "name": "vite-react-npm-package",
  "version": "1.0.0",
  "type": "module",
  "main": "./dist/index.umd.cjs",
  "module": "./dist/index.js",
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "require": "./dist/index.umd.cjs"
    }
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "storybook": "storybook dev",
    "build": "vite build",
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "devDependencies": {
    "@storybook/react-vite": "^10.3.5",
    "vite": "^8.0.10"
  }
}

Publish

Now that we have completed the development of our package, we will learn how to publish it into the npm registry. For this, we need to access our npm account (if you don't have one yet, you can sign up here) with the command npm login.

Once we are logged in, we need to update the version number of our package in the package.json file. Then, we can generate the build of our project and publish it with the command npm publish --access public (with an npm subscription, we can also publish private packages).

To simplify the publication process, we can add the script "publish": "npm run build && npm publish --access public" to our package.json file. Then, to publish a new version of our package, we only need to update its version number and run the command npm run publish.

Our package.json file should now have the following code:

package.json
{
  "name": "vite-react-npm-package",
  "version": "1.0.0",
  "type": "module",
  "main": "./dist/index.umd.cjs",
  "module": "./dist/index.js",
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "require": "./dist/index.umd.cjs"
    }
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "storybook": "storybook dev",
    "build": "vite build",
    "publish": "npm run build && npm publish --access public"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "devDependencies": {
    "@storybook/react-vite": "^10.3.5",
    "vite": "^8.0.10"
  }
}

Conclusion

We have now completed the setup of our React npm package with Vite and Storybook. If you would only like to see the completed code of this tutorial, you can find it here.