We use Lit.js to create our web components because it streamlines the development of reusable UI elements and enhances performance through its reactive programming model. Its lightweight design and powerful templating capabilities enable us to build efficient and maintainable components. For more information, check out the Lit.js documentation.
- Create a new folder in the
libs/components/srcdirectory. Name it according to the component you are creating, e.g.,badge. - Create a TypeScript file in the folder, naming it after the component, e.g.,
badge.ts. - Create an SCSS file in the same folder, also named according to the component, e.g.,
badge.scss.
At the top of your new component file, import your styles and the necessary modules from Lit.js, then define your component using the @customElement decorator:
import { LitElement, html, css, unsafeCSS } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import styles from './badge.scss?inline'; // Adjust the path as needed
/**
* CovalentBadge
*
* @slot - This element has a slot for content
*/
@customElement('cv-badge')
export class CovalentBadge extends LitElement {
static override styles = [
css`
${unsafeCSS(styles)}
`,
];
// Define properties here if needed
@property({ type: String }) myProperty = '';
render() {
return html`
<div class="badge">
<slot></slot>
</div>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'cv-badge': CovalentBadge;
}
}
export default CovalentBadge;For more details on defining a component, follow the Lit.js defining a component guide.
Note: The class name should begin with Covalent, and the component selector should start with cv-.
Define your styles in the SCSS file. Ensure you follow best practices for styling and maintain consistency with the design system.
Add comments throughout your code to explain the purpose of the component, its properties, and any slots it may have. This documentation will assist other developers in understanding how to use the component effectively.
- Create a
.stories.jsfile in the component folder, naming it according to the component, e.g.,badge.stories.js. Refer to the storybook documentation for guidance on creating stories for web components.
import './badge';
export default {
title: 'Components/Badge',
argTypes: {
size: { options: ['large', 'small'], control: { type: 'select' } },
},
args: {
size: 'large',
content: '33',
},
};
const Template = ({ content, size }) => {
return `<cv-badge size="${size}">${content}</cv-badge>`;
};
export const Basic = Template.bind({});Manual testing
- Run Storybook by executing the command
npm run storybookto ensure the component renders correctly. - Test all properties and slots within the component.
- Check for any console errors and resolve them as necessary.
Unit tests
- Create a new test file in the component folder. Name it according to the component you are creating, e.g.,
badge.spec.ts. - Add unit tests in the test file. Tests should follow the vitest framework. Refer to Vitest Documentation for more details.
Example test case:
/**
* @vitest-environment jsdom
*/
import { it, describe, expect, beforeAll } from 'vitest';
import { CovalentBadge } from './badge';
describe('Covalent Badge', () => {
it('should work', () => {
expect(new CovalentBadge()).toBeDefined();
});
});- Run tests: To execute the tests, use the following command:
npx nx run components:test- Open libs/components/component-config.json and add component details as follows:
-
name:
The class name of the component, as defined in the component file. -
selector:
The selector for the component. -
path:
The relative path to the component file. -
events:
A list of events dispatched by the component.Important: Always include events here!
React wrapper components will not listen to events unless they are explicitly listed in this property.
[
...,
{
"name": "CovalentBadge",
"selector": "cv-badge",
"path": "./badge/badge",
"events": ["change", "action"]
},
...
]Run the following command:
nx run components:build-exportsWhat it does:
- Updates the
libs/components/package.jsonfile with the correct exports. - Updates the
libs/components/src/index.tsfile to include the necessary exports.
Important: After running this command, verify the changes in both files to ensure the exports are accurate.
Run the following command:
nx run components-react:generate-react-wrappersWhat it does:
- Creates a React wrapper component and its corresponding test file in the
libs/components-react/srcfolder. - Updates the
libs/components-react/src/index.tsfile to include the new React wrapper component.
Note: Review the generated React wrapper components and test files to ensure correctness. Run the following command to test the react wrapper component:
nx run components-react:testOnce everything is complete, include all the files and create a pull request using the new web component template.