In this post, we focus on creating reusable CSS components using Bit. Bit allows us to encapsulate styling rules into independent components that can be shared and managed across different projects.
These CSS components can be used in various environments, regardless of the frameworks in use - React, Angular, Vue, or others. The compatibility of Bit with diverse styling solutions enhances its flexibility, and we will use SCSS as a representative example in this context.
The creation of independent components promotes reusability and consistency in your design system and UI library. Beyond that, Bit also allows us to compose these components together, enabling more complex structures while maintaining modularity.
One of the notable benefits of using Bit is its support for incremental updates. This allows for iterative improvements of components without affecting existing project structures. In the following sections, we will walk through the process of creating these components and demonstrate how they can be composed and updated incrementally.
Our demo includes 3 SCSS components:
These 3 SCSS components compose the blocks/container component, which defines a container with a background color, padding, and media queries for different screen sizes.
This blog uses SCSS/CSS component templates, provided by the HTML env. These templates provide the basic structure for creating SCSS/CSS components, and are configured to use the HTML env, which is a framework-agnostic environment for frontend components.
"teambit.generator/generator": {
"envs": ["teambit.html/html-env", "teambit.react/react-env"]
},
We also added the react-env so we can use it later to generate a React component.
First, let's create a SCSS component variables/colors that defines color schemes for consistent color usage across your applications:
The implementaion of this component is very straightforward. We define two variables, primary and secondary, and export them as a map:
/* @filename: colors.module.scss */
$primary-color: #007bff;
$secondary-color: #6c757d;
:export {
primary: $primary-color;
secondary: $secondary-color;
}
Much like other Bit components, CSS components require a main file or entry file, to expose their API. In this case, the main file will export the color constants as follows:
/* @filename: index.ts */
import colors from './_colors.module.scss';
export const { primary, secondary } = colors;
Next, we'll create a layout/spacing component that includes a function for calculating spacing and our base spacing variable:
In this example, we define a base spacing variable and a spacing function that multiplies the base spacing by a given multiplier. We then export the base spacing variable and the spacing function as a map:
/* @filename: spacing.module.scss */
$base-spacing: 10px;
@function spacing($multiplier) {
@return $base-spacing \* $multiplier;
}
:export {
base: $base-spacing;
}
Then, we create a layout/breakpoints component that defines different screen sizes and includes a series of mixins for different media queries:
/* @filename: breakpoints.module.scss */
// breakpoint sizes
$xs: 360px;
$sm: 480px;
$md: 768px;
$l: 920px;
$lg: 1200px;
$xl: 1440px;
$xxl: 1920px;
// exporting sizes to be used via js
:export {
xs: $xs;
sm: $sm;
md: $md;
l: $l;
lg: $lg;
xl: $xl;
xxl: $xxl;
}
// generic media query mixin. do not use directly
@mixin media($breakpoint) {
@media only screen and (max-width: $breakpoint) {
@content;
}
}
// media queries for each size to be used directly
@mixin media-xs {
@include media($xs) {
@content;
}
}
@mixin media-sm {
@include media($sm) {
@content;
}
}
// (continue for all sizes)
In this example, we're creating an independent component called blocks/container that uses the SCSS components we created in the previous section:
This SCSS file demonstrates how to utilize the SCSS functions, mixins, and variables defined in separate, independent SCSS components. By sharing and reusing these components across the entire organization, you can ensure design consistency and reduce code duplication.
// container.module.scss
@use '@teambit/your-organization.colors/colors.module.scss' as colors;
@use '@teambit/your-organization.spacing/spacing.module.scss' as spacing;
@use '@teambit/your-organization.breakpoints/breakpoints.module.scss' as
breakpoints;
.container {
background-color: colors.$primary-color;
padding: spacing.spacing(2);
@include breakpoints.media-md {
padding: spacing.spacing(4);
}
@include breakpoints.media-lg {
padding: spacing.spacing(6);
}
}
Bit maintains the independence of each component, while keeping track of the dependencies between them. This allows us to compose these components together to create more complex structures, while maintaining modularity.
Next, let's dive into how we can utilize the container style in various environments, such as React, Angular, and Vue components managed by Bit. Bit empowers us to create independent, reusable components that can be seamlessly integrated into different projects and frameworks.
Let's start by examining how we can utilize the container style in a React Bit component
// React.tsx
import { ReactNode } from 'react';
import { container } from '@learnbit/css.blocks.container';
export type ReactProps = {
/**
* a node to be rendered in the special component.
*/
children?: ReactNode,
};
export function ReactExample({ children }: ReactProps) {
return <div className={container}>{children}</div>;
}
In the example above, we import the container.module.scss
file, assigning the container class from the imported styles object to our component's div. This applies the styles defined in the container class to our React component.
Now, let's delve into how we can utilize the container style in an Angular Bit component.
We'll skip the component creation step, as it's identical to the React component creation process (you'll have to add the teambit.angular/angular
env to the generator's envs array in the workspace.jsonc file, though).
<!-- my-component.component.html -->
<div class="container">Content goes here</div>
/* my-component.component.scss */
@use '@learnbit/css.layout.container/container.module.scss' as container;
.container {
@include container.container;
}
With Angular, we can directly employ the container class in the component's HTML template. To apply the styles from the container.module.scss file, we import it as container and then include the container class using the @include directive in the component's SCSS file.
Finally, let's explore how we can utilize the container style in a Vue Bit component:
<!-- MyComponent.vue -->
<template>
<div class="container">Content goes here</div>
</template>
<style scoped lang="scss">
@use '@learnbit/css.layout.container/container.module.scss' as container;
.container {
@include container.container;
}
</style>
In Vue, we define the container class directly in the component's template. To apply the styles from the container.module.scss file, we import it as container and include the container class using the @include directive in the component's scoped SCSS block.
By leveraging Bit's component-based approach, along with the shared styles, we can maintain consistency across various projects and frameworks, while ensuring that each team retains their autonomy.
The next essential feature of Bit we will look at is its ability to manage incremental builds and automatic tagging. This is one of the key capabilities that allow Bit to maintain consistency and modularity across multiple projects and frameworks.
Consider a scenario where we make an update to the spacing style. As soon as we tag this change, Bit is smart enough to recognize that any component dependent on this spacing style, like our container, needs to be rebuilt and versioned as well.
This cascading effect even extends to the framework-specific components that are utilizing the container style. This means, if we have a React, Angular, or Vue component using the container style, Bit will automatically rebuild, retest, and version these components as well.
Let's see this in action:
// spacing.module.scss
$base-spacing: 8px;
@function spacing($multiplier) {
@return $base-spacing \* $multiplier;
}
:export {
base: $base-spacing;
}
This kind of intelligent dependency management is what makes Bit such a powerful tool for building and managing reusable components across various projects and frameworks.
Throughout this blog post, we've walked you through the process of creating, composing, and leveraging reusable CSS components with Bit. By encapsulating our styling rules into distinct, standalone units, we've achieved significant strides towards a consistent, maintainable design system.
Bit's capacity to support a broad range of frameworks allows these components to be integrated seamlessly into diverse projects. Whether it's React, Angular, Vue, or others, the use of these components remains consistent and straightforward.
Furthermore, Bit's intelligent dependency management and automatic tagging system enable incremental updates without affecting the overall project structure. This feature ensures that all dependent components are automatically versioned and updated when a change is made, thus reducing manual overhead and potential inconsistencies.
In essence, Bit empowers teams with true autonomy, while maintaining a synchronized, up-to-date state across all projects and frameworks. This balance between independence and consistency is a key enabler of efficient collaboration and code reuse.
By incorporating Bit into your development workflow, you're investing in a more efficient, consistent, and manageable codebase. Whether you're building a complex design system or a small UI library, Bit's reusable CSS components will undoubtedly prove to be a valuable asset.