# TIL - How to write a web component with SolidJS

Today, I wanted to test the library: [SolidJS](https://www.solidjs.com/). It features JSX support and is known for its great performance.

## Install the lib

The first step I did was to follow the [Getting Started](https://www.solidjs.com/guide#getting-started) guide and start from a given template:

```sh
> npx degit solidjs/templates/ts my-app
> cd my-app
> npm i
```

## Remove the unnecessary files

I removed all content from `src/` folder and created an empty `index.ts`.

This file will serve as an entry point for the lib.

## Update Vite's configuration

In `vite.config.ts`, I added the `lib` configuration:
```js
export default defineConfig({
  plugins: [solidPlugin()],
  build: {
    lib: {
      entry: path.resolve(__dirname, 'src/index.ts'),
      name: 'my-component',
      fileName: (format) => `my-component.${format}.js`
    },
    // ...
  },
});
```

With the `lib` property, Vite provides a way to bundle a library from the given entry point. 
This [library mode](https://vitejs.dev/guide/build.html#library-mode) still gives you access to the demo page with `npm run start`.

## Creating the component

I then created a file for my component.

```tsx
// src/MyComponent.tsx

const MyComponent: Component<Props> = (props) => {
   return <> {/*...*/} </>;
}
```

And I did not export the component like I am used to with react, but I rather registered it with the `customElement` helper from the `solid-element` module.

> The `solid-element` is a separate module that needs to be installed.

```ts
// src/MyComponent.tsx
import { customElement } from "solid-element";

/* ... */
customElement("my-component", { someProp: "defaultValue" }, MyComponent)
```

The custom `customElement` helper works by giving the module a tag name (e.g. `"my-component"`) and binding it to your component (e.g. `MyComponent`).

> You need to pass as a second argument the default props values. Omitting this object prevents the props from receiving data from their corresponding attribute (e.g. `some-prop` attribute should bridge data to `someProp` prop).

### A note about styles

Vite allows writing [css-modules](https://github.com/css-modules/css-modules) files (e.g. `MyComponent.module.css`) in order to scope the style to a specific component. Because of the Shadow DOM, styles written in the web component are scoped to the web component by default. That means, in this case, I do not need to rely on the css-modules feature.

In order to add style to my component, I wrote a standard CSS file and import it into the component file.

```ts
import styles from "./MyComponent.css";
```

The `styles` object is the actual styles string and can be embedded into the web component using the `<style>` tag.

```tsx
const MyComponent: Component<Props> = (props) => {
    return <> 
        <style>{styles}</style>
        {/*...*/}
    </>;
}
```

Because class names are kept untouched by Vite, I can add class names as I would normally do in an HTML markup:

```tsx
<div class="myComponent" />
```

### Last step

After setting up my component, I imported the component file in the `index.ts` file.

```ts
// src/index.ts
import "./MyComponent.tsx";
```

I then added the custom web component in the markup of the `index.html` file (Vite's "demo" page).

```html
<body>
    <my-component some-prop="someValue">
</body>
```

Everything looked fine. I then built the lib (`npm run build`) and got three files.
- `style.css`: can be ignored because style is also embedded in the JS.
- `my-component.es.js`: the ES module output JS
- `my-component.umd.js`: the universal module output JS

> Both modules seem to work fine when imported into an HTML document, but the UMD is way smaller because minified.

## Conclusion

This process is quite straightforward once you know what needs to be configured. I think it is a good starting point, for me, to learn SolidJS and to dip a toe in the web components world.


