Reuse and share React components across your applications and projects for faster, consistent UI development.

Medium.com/media/15666…

This short tutorial is based on the official React with Bit tutorial by Debbie O’Brien for re-using components. It will help you save development time, improve consistency, and make it easier to maintain your code base.

It will teach you through practice a super efficient way to develop reusable components and use them in a scalable, manageable way across projects. We use this workflow to build our entire system, including all the applications and products — just like Lego. It is not only faster, but also easier to maintain.

Once done, you will have several components (‘ buttons’ and ‘cards’ to use the buttons) that will be’ exported ‘from one project and used in another.

  • Base-UI / UI / Card
  • base-ui / ui / button

With the latest “harmony” version of bits, you will develop decouple and independently reusable components in your projects. Harmony will provide you with a simple development experience to achieve this “singleton like” development, and will automate all configuration and definition for you. There is also no Repo Efactoring.

You will then export (push/publish) these components remotely and use them from another project as a package (NPM/YARN) or cloned source code. But that’s not all; You’ll learn how to easily customize and add MDX documents, render examples, quarantine tests, and more.

Example – Complete React e-commerce application as a reusable component

This approach is very effective and can be applied to any project in the future, from component libraries to real world applications in React. So let’s jump in and get started, covering the steps one by one.

  1. Install the bit
  2. Start a workspace
  3. Create components
  4. Version and export (push/publish) components
  5. In the form of packages installed components | import (clone/la) components
  6. Bonus: Putting components together

Let’s get started!

1. Install bits

To use Bit, we first need to install BVM, the Bit version manager.

npm i -g @teambit/bvm
Copy the code

We can then use it to install bits

bvm install
Copy the code

You can check if the Bit is installed by running the BVM version command. If you run into any problems, check out “Using BVM”, as you may need to configure the PATH global variable.

2.2. Initialize a workspace

The Bit workspace is where the magic happens. It’s where you develop and compose components in Bit. A Bit workspace turns any project into a multi-component project while making development easy in all aspects.

Let’s initialize a new Bit workspace using the latest “harmony” version of Bit. It is best to initialize a workspace with Git for version control in an empty directory. Go to that directory and run.

Bit init -- harmonyCopy the code

This command creates a workspace. Jsonc file, a.bitmap file (which is automatically generated and mapped to components in the workspace), and a.bit directory, which is typically located in a.git folder when you use git.

This folder should be ignored by Git, while the workspace. Jsonc and bitmap files should be version controlled.

Install dependencies

Run the bit install command to install all required dependencies.

bit install
Copy the code

Since we will be using React, we need to install React and React -dom as peer dependencies. Peer dependencies provide the details to be provided by the host application.

Bit install react- type peer & bit install react-dom - type peerCopy the code

Configuring the Workspace

The workspace. Jsonc file is how we configure everything for our workspace. You can change the name and icon to personalize the workspace.

The default range is set to “my range”. You will need to change this later so that you can export the component to the correct scope.

The variation part is how we set up our environment. Here, we need to uncomment the React line so that all of our components will use the React environment instead of the default Node environment.

# workspace.jsonc
Copy the code
"teambit.workspace/variants": {
Copy the code

In this example, we use wildcards to select all components, but you can have many variations depending on your needs, selecting only specific directories or omitting directories. See the variation documentation for more details.

3. Create a component

When creating a component, the Bit requires that all component files be contained in its own directory and exported using an index file. The files contained in this directory should contain the code for the component as well as the tests, documentation, composition, and styles (if required).

To make it easier, Bit knows how to generate these files for you, so all you have to do is choose a name and namespace for your component.

Create a component named Button in the UI namespace.

bit create react-component ui/button
Copy the code

We now have a button directory with various files. Let’s take a quick look at the content created.

Component files

The button.tsx file contains the code for the button. It’s just one with text

Because the generator only gave you one example, but now you can modify this component to do anything we want.

Note the comments in items — these are important because they show up under the properties TAB of the Workspace UI and make it easier for others to understand your component and how it should be consumed.

# button.tsx
Copy the code
import React from 'react';
Copy the code
export type ButtonProps = {
Copy the code
export function Button({ text }: ButtonProps) {
Copy the code

Composite file

A composition is an example of a component that is rendered separately, alone or in the context of another component or even an application.

The button.com Position. TSX file contains our portfolio. This file imports the button component so we can see what it looks like. We can add various combinations here, such as primary button combinations and secondary button combinations.

# button.composition.tsx
Copy the code
import React from 'react';
Copy the code
export const BasicButton = () => <Button text="hello from Button" />;
Copy the code

The test file

Button.spec.tsx is how we test our components. We import from the combo file because we want to test our various combinations, such as whether the button is the main button or an item has been passed.

#  button.spec.tsx
Copy the code
import React from 'react';
Copy the code
it('should render with the correct text', () => {
Copy the code

Our component uses the React test library, so we need to install it so that our tests can run.

bit install @testing-library/react
Copy the code

Document file

The button.docs.mdx file is where we document our components. We can modify our component descriptions and labels to better categorize our components, which we use when searching for components.

Because it’s an MDX file, we can import our component and then use the live playground feature to show consumers of our component how to use it, let them play with the component on the spot, change some things and see how it works.

# button.docs.mdx
Copy the code
---
Copy the code
import { Button } from './button';
Copy the code
## React Component for rendering text
Copy the code
A basic div that renders some text
Copy the code
### Component usage
Copy the code
```js
Copy the code
### Using props to customize the text
Copy the code
Modify the text to see it change live:
Copy the code
```js live
Copy the code

Index file

The index.tsx file exports the component. Here we use the named exit to export the component and its props.

# index.ts
Copy the code
export { Button } from './button';
Copy the code

4. Start the development server

Before we start, let’s make sure our component works by running the bit status command.

bit status
Copy the code

To resolve the problems found, we can run the bit compile command, which will compile our component and create the missing dist folder.

The start command starts our development server, compiles our components and uses hot module replacement to observe changes. It runs different workspace tasks through the worker, such as tests, Linters, and any workspace tasks defined by the component.

bit start
Copy the code

Exploring the user interface

When we first run this command, it will take some time to load because it is building the entire user interface, which contains not only one of your components, but many other interesting things, which we will explore below.

Summary of gallery

The gallery page contains galleries for all of our components. In our case, we only have one. We can also see a preview of our components.

An overview of the label

Clicking on the component opens it on the Overview TAB, which is made up of our documentation files. Since our document includes a live playground, you can modify the text and see it change in real time. This is just a simple example, so it’s not very exciting, but for more complex components, you can change various items on the spot and see what the components look like, which is very useful.

The overview TAB also includes the composition and properties of your component. These properties come from comments in your component items.

Combination TAB

If you have a variety of different combinations, you’ll see a list on the right and you can click on any one you want to see. You’ll also notice an icon at the top of the component that allows you to open the component in full-screen mode so that you can see it outside of the user interface in your workspace.

The test label

The tests TAB shows whether our tests passed or failed. Since we are running the local development server, if we modify our test and make it fail, this will automatically turn red and show that your test has failed. This means you don’t need to run any test commands on the terminal to see if your tests pass or fail, because you can see them directly in the user interface.

The important thing to note here is that if your test fails and you try to export your component, then you will see a message on the terminal that you will not be able to export your component until the test passes. This encourages developers to write tests and therefore best practices.

Dependency label

The dependency TAB shows the dependencies of your component. Since our component doesn’t depend on any other components, there’s nothing to show here, but once we start composing components from other components, this diagram becomes very useful.

Code icon

On the right side of the user interface, you’ll also see some ICONS. The code parentheses show our component code. This is very useful when components are exported, because the code can be easily examined without having to open the code editor. Consumers of your component may want to see the code before consuming it. This is also helpful for fixing bugs or getting feedback on your code.

You’ll also notice that under the list of component files, it shows the dependencies of the component. This shows the other components it depends on, as well as packages such as the test library.

Update log icon

Since we have not yet exported our component, this TAB will show instructions on how to export it. Once your component is exported, you will see a list of component versions here, along with any information that was submitted when the component was versioned.

Styling components

Now it’s time to modify our component and turn it into a real button. First of all, we can take

Element changes to element, and then we can add some basic styling to our buttons. We’re going to use
CSS moduleDo local scope design, but use SCSS extensions so we can use them
SassNesting.

Since we want to show the major and minor changes to our buttons, we’ll use HTML data attributes, which allow us to store information about HTML elements. We also need to add data-attributes to our button elements so that we can use them to set primary and secondary changes to the button.

# button.module.scss
Copy the code
.button {
Copy the code
&[data-variation='primary'] {
Copy the code
&:hover {
Copy the code
&[data-variation='secondary'] {
Copy the code
&:hover {
Copy the code

To use our style on our buttons, we need to import the file, which we can then use by referencing style.button as className.

Import the style

# button.tsx
Copy the code
import styles from './button.module.scss';
Copy the code

You may notice a warning in vscode that it cannot find the CSS module or its type declaration for this file. Feel free to ignore this warning.

Set the variant

We can then set a variant of the item with the optional value primary or Secondary. When we pass our item, we can give it a default value of primary, which means that if the consumer does not add a variant for the button, it will default to the primary variant. Then, we add our className, passing in our button class from the style we just imported. To make it work, we need to add our data variables, passing in the values of the variable items we created.

We should also modify the text item to make it more explicit, so that if we had another item called text, we wouldn’t have any problems. Let’s change it to ‘buttonText’.

# button.tsx
Copy the code
import React from 'react';
Copy the code
export type ButtonProps = {
Copy the code
export function Button({ buttonText, variation = 'primary' }: ButtonProps) {
Copy the code

Now that we have the development server running, we can check how our component looks on localhost:3000.

Create a composite

We can now create another combination for our secondary button. First, let’s rename BasicButton to PrimaryButton, because that’s the name our component will display in the user interface. We don’t need to add a variable to the main button because we already have a default value primary. We can then copy and paste this combination, rename it SecondaryButton, and change the value of the variant item to Secondary.

export const PrimaryButton = () => (
Copy the code
export const SecondaryButton = () => (
Copy the code

Now in our local workspace, you’ll see that we have two combinations, and in the combination TAB, we can choose between the primary button and the secondary button.

The overview TAB now shows our Button combination and the types and defaults for the new variation items.

To improve our documentation, we can update live code blocks with secondary button examples to make it easier for our consumers to play with these items and see the changes to the buttons.

```js live
Copy the code

Since we modified our composition, you may notice that our test now fails because it can no longer find the BasicButton composition. We can fix our tests, or we can test each variation.

# 
Copy the code
import
Copy the code
import
Copy the code
import
Copy the code
it('should render with the correct text', () => {
Copy the code
const
Copy the code
const
Copy the code
expect(rendered).toBeTruthy();
Copy the code
});
Copy the code
it('should render with the correct text', () => {
Copy the code
const
Copy the code
const
Copy the code
expect(rendered).toBeTruthy();
Copy the code
});
Copy the code

4. Construct components

Let’s create a basic card component that consumes the button component. We can use the bit create command to generate another component, which we will call card.

bit create react-component ui/card
Copy the code

Then we can restart the development server so that we can see our new components.

bit start
Copy the code

For now, our card component is just a basic DIV, so let’s modify this component by adding some styles using CSS modules.

# card.module.scss
Copy the code
.card {
Copy the code
button {
Copy the code

We can then import our style into our card component.

# 
Copy the code
import
Copy the code

Then add those styles to our

Element.

export function Card({ text }: CardProps) {
Copy the code

Import our component

To add our button to the card component, we need to import it first. Bit does not allow the use of relative imports, even if both components are in the same directory. The reason is that they might be in the same directory today, but not tomorrow. This allows you to easily change your code directory structure without messing up your component imports because your components are already decoupled from the workspace directory structure. To import this component, we need to find its package name, which we can see in the component’s overview TAB.

Once we import it, we can use it in our card component, and we can also import button items and extend our card items to include them in button items.

# card.tsx
Copy the code
import React from 'react';
Copy the code
export type CardProps = {
Copy the code
export function Card({ text, buttonText, variation }: CardProps) {
Copy the code

We can then update our combo file to include new items.

# card.composition.tsx
Copy the code
import React from 'react';
Copy the code
export const BasicCard = () => (
Copy the code

We can also update our document instance with new items for our button component.

# card.docs.tsx
Copy the code
```js live
Copy the code

Now we can see under the local workspace dependencies TAB that our card component is consuming the button component. We can also see in dependencies that our diagram now includes both components and shows that the card depends on the button component.

Of course, we can create another combination of our components by adding or omitting the word primary, since primary is the default.

export const PrimaryCard = () => (
Copy the code

Create a remote scope

To export the component, we need to have a scope set up. We can do this by visiting bit.dev and creating an account or logging in (if you’ve already set up one).

bit login
Copy the code

Once you are logged in, you can create a new scope/collection. Since our components are UI components, they probably should be in a scope called base-UI, so let’s create this collection.

Update your default scope

Once we have created our scope, we will need to update the scope name in the workspace. Jsonc file to make it the same as yours. A scope name is a combination of your organization or team name and the collection name.

# workspace.jsonc
Copy the code
defaultScope: <user-name>.<scope-name>
Copy the code

Link your node modules#

Since we have changed the default range, we now need to ensure that our node modules are properly linked. We can do this with the bit Link command.

bit link

copy

Now in our node module, we can see that we have these components in the correct scope.

We now need to manually update our import statement to reflect the changed scope name.

Import {Button, ButtonProps} from '@dbs-obrien /base-ui.ui.button';Copy the code

Version management of components

We can run the bit status command to see the status of our component.

bit status
Copy the code

We can see that we are missing the dist folder, which we need in order for our components to work properly when exported. Let’s solve this problem by running the bit compile command.

bit compile
Copy the code

Now, if we use bit Status, it will show that our component is fine, which means we are ready to use the bit Tag command to create the first version of our component. Using the –all flag, we can mark all versions that have been changed, which means we don’t have to mark each version individually. We can also add a message to our component version.

Bit tag - all - patch - Message "First version"Copy the code

Export components

Once the component has been tagged and all the tests have passed correctly, you will have a new version of the component, so you can export the component using the bit export command.

bit export
Copy the code

Once your components are exported, they will now be available on bit.dev, so they can be used by other members of your team, and by anyone if you set the scope to public.

You can also see in the Changelog TAB that your component now has its first version, with the version information you set when you marked it.

In the code TAB of the card component, you can see a list of dependencies under the code file from which you can click on the component it depends on, in our case the button component.

Installing the component

We can install our component into another application using YARN or NPM. Let’s create a simple React application.

npx create-react-app use-card
Copy the code

We can then install the component using the yarn or NPM install command, followed by the package name of the component. To install components with the package manager, the package manager needs to access your components like packages in the registry, so you need to configure your scope as a scope registry. Details of this can be found under the Use button, and then select the Install TAB, because we want to install the component using the package manager.

After you click the link, copy the code and paste it into the terminal to configure the scope as a scoped registry. You only need to set it up once. Once done, you can add your components from the scope registry/bit cloud.

yarn add @debs-obrien/card.ui.card
Copy the code

Now in your node_modules folder, you’ll see that we’ve installed this component so it can be used just like any other NPM package. Since we installed the card component that depends on the button component, you will see that the button component is also installed.

If you look at the file, you’ll see that this component is not a compiled component, which means that the sASS file is still an SASS file, so if we want to use it in our React application, we’ll need to include the package it depends on, which in this case is Sass.

yarn add sass
Copy the code

Consume the component

Let’s import it into our application.

# App.js
Copy the code
import logo from './logo.svg';
Copy the code
function App() {
Copy the code
export default App;
Copy the code

Thus, our beautiful card component is rendered in our React application.

That’s it. Now is the time to start creating more components and using them in many of your applications and teams.

To learn more

  • How did we build the microfront end
  • Build the React component library — the right way
  • Build a React design system for easy adoption and extension


How We Reuse and Share React Components was originally published in Bits and Pieces magazine, and people continued the conversation by highlighting and responding to the story.