Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/nathanjhood/ts-web-components
How to OOP in the browser; with types.
https://github.com/nathanjhood/ts-web-components
no-config nodejs tailwindcss typescript web-component web-component-starter web-components
Last synced: 28 days ago
JSON representation
How to OOP in the browser; with types.
- Host: GitHub
- URL: https://github.com/nathanjhood/ts-web-components
- Owner: nathanjhood
- Created: 2024-10-13T20:21:12.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2024-10-18T00:46:11.000Z (29 days ago)
- Last Synced: 2024-10-18T17:44:28.542Z (28 days ago)
- Topics: no-config, nodejs, tailwindcss, typescript, web-component, web-component-starter, web-components
- Language: TypeScript
- Homepage: https://nathanjhood.github.io/ts-web-components/
- Size: 220 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Typescript Web Components
Typed OOP in the browser!
```html
(...)
"Your App Goes Here!"
```
- No config
- No framework
- No abstractionsJust raw [Web API](https://developer.mozilla.org/en-US/docs/Web/API).
Powered by Typescript, TailwindCSS, ESBuild, and fast-refreshing development server!
## How to...
Step by step!
- [`start`](#start)
- [`class AppComponent {}`](#class-appcomponent-)
- [`AppComponent.constructor()`](#appcomponentconstructor)
- [`AppComponent extends HTMLElement`](#appcomponent-extends-htmlelement)
- [`HTMLElement.super()`](#htmlelementsuper)
- [`this`](#this)
- [`AppComponent.innerHtml`](#appcomponentinnerhtml)
- [`CustomElementRegistry`](#customelementregistry)
- [`'app-component': AppComponent`](#app-component-appcomponent)
- [`AppComponent.render()`](#appcomponentrender)
- [`AppComponent.render(innerHTML)`](#appcomponentrenderinnerhtml)
- [`AppComponent.setup()`](#appcomponentsetup)
- [`createElement('app-component')`](#createelementapp-component)
- [`App()`](#app)
- [`render(App)`](#renderapp)
- [``](#app-component)
- [Tips](#tips)
- [Further Reading](#further-reading)### `start`
```sh
$ git clone [email protected]:nathanjhood/ts-web-components.git
``````sh
$ cd ts-web-components
``````sh
$ npm install
``````sh
# For Windows...
$env:NODE_ENV="development"# For Linux/Mac...
export NODE_ENV="development"
``````sh
$ npm run start
```
```sh
# ...Rebuilding...
Done in 1623ms.
Server running at http://127.0.0.1:3000/
To exit: Ctrl + c```
[Open in your browser](http://localhost:3000) and edit `src/App.ts` - the page will automatically refresh itself after every save.
---
### `class AppComponent {}`
```ts
// src/App.tsclass AppComponent {}
```---
### `AppComponent.constructor()`
```ts
class AppComponent {
constructor() {/** setup goes here... */}
}
```---
### `AppComponent extends HTMLElement`
```ts
// "I am a HTMLElement"class AppComponent extends HTMLElement {
constructor() {}
}// "...plus more ;) "
```---
### `HTMLElement.super()`
```ts
class AppComponent extends HTMLElement {
constructor() {
super(); // MUST do this first...
}
}
```---
### `this`
```ts
class AppComponent extends HTMLElement {
constructor() {
// inside here, "this" means "this 'AppComponent'"...super();
this. // <-- '.' should produce a long list of props and methods...
}
}
```---
### `AppComponent.innerHtml`
```ts
// 'innerHTML' === innerHTMLclass AppComponent extends HTMLElement {
constructor() {
super();
this.innerHTML = `Your app goes here`;
}
}
```### `CustomElementRegistry`
```ts
// IMPORTANT
window.customElements.define('app-component', AppComponent);
```---
### `'app-component': AppComponent`
```ts
window.customElements.define('app-component', // <-- wrap the class!
class AppComponent extends HTMLElement {
constructor() {
super();
this.innerHTML = `Your app goes here`;
}
}
); // <-- '.define()' ends here!
```---
---
### `AppComponent.render()`
```ts
window.customElements.define('app-component',
class AppComponent extends HTMLElement {
constructor() {
super();
this.innerHTML = this.render();
}
render() {
return `Your app goes here`;
}
}
);
```---
### `AppComponent.render(innerHTML)`
```ts
window.customElements.define('app-component',
class AppComponent extends HTMLElement {
constructor() {
super();
this.innerHTML = this.render('Your app goes here');
}
render(innerHTML: string): string {
return `${innerHTML}`;
}
}
);
```---
### `AppComponent.setup()`
```ts
window.customElements.define('app-component',
class AppComponent extends HTMLElement {
constructor() {
super();
this.setup();
}
setup(): void {
this.innerHTML = this.render('Your app goes here');
}
render(innerHTML: string): string {
return `${innerHTML}`;
}
}
);
```---
### `createElement('app-component')`
```ts
window.customElements.define('app-component',
class AppComponent extends HTMLElement {
constructor() {
super();
this.setup();
}
setup(): void {
this.innerHTML = this.render('Your app goes here');
}
render(innerHTML: string): string {
return `${innerHTML}`;
}
}
);const app = document.createElement('app-component');
```---
### `App()`
```ts
const App = () => {
// define the component
window.customElements.define('app-component',
class AppComponent extends HTMLElement {
constructor() {
super();
this.setup();
}
setup(): void {
this.innerHTML = this.render('Your app goes here');
}
render(innerHTML: string): string {
return `${innerHTML}`;
}
}
);
// then return it
return document.createElement('app-component');
}// Now we can assign it :)
const app = App();
```---
### `render(App)`
```ts
// src/index.tsimport App = require('./App');
const render = (element: () => HTMLElement) = {
// ...attaches passed-in element to document
}// so, pass it our App :)
render(App)```
---
### ``
```html
```
```html
#shadowRoot (open)
"Your App Goes Here!"
```
## Tips
---
### functional approach
```ts
// example:const Button = (): HTMLButtonElement => {
return document.createElement('button')
}// HTMLButtonElement
const button = Button();```
---
### factory method
```ts
// exampleconst CustomButton = () => {
class CustomButtonElement extends HTMLButtonElement {
constructor() {
super();
}
}
customElements.define('custom-button', CustomButtonElement)
return document.createElement('custom-button') as CustomButtonElement;
};// CustomButtom
const customButton = CustomButton();
```---
### passing props
```ts
type CustomButtonProps = {
type: 'submit' | 'reset' | 'button';
};const CustomButton = (props: CustomButtonProps) => {
class CustomButtonElement extends HTMLButtonElement {
constructor() {
super();
this.type = props.type;
}
}
customElements.define('custom-button', CustomButtonElement);
return document.createElement('custom-button') as CustomButtonElement;
};const customButton = CustomButton({ type: 'submit' });
```
---
### adding children
```ts
type CustomButtonProps = {
type: 'submit' | 'reset' | 'button';
children?: Node;
};const CustomButton = (props: CustomButtonProps) => {
class CustomButtonElement extends HTMLButtonElement {
constructor() {
super();
this.type = props.type;
if (props.children) this.appendChild(props.children);
}
}
customElements.define('custom-button', CustomButtonElement);
return document.createElement('custom-button') as CustomButtonElement;
};const customButtonA = CustomButton({ type: 'submit' });
const customButtonB = CustomButton({ type: 'submit', children: customButtonA });```
---
### adding styles
```ts
type CustomButtonProps = {
type: 'submit' | 'reset' | 'button';
children?: Node;
className?: string;
};const CustomButton = (props: CustomButtonProps) => {
class CustomButtonElement extends HTMLButtonElement {
constructor() {
super();
this.type = props.type;
if (props.children) this.appendChild(props.children);
if (props.className) this.className = props.className;
}
}
customElements.define('custom-button', CustomButtonElement);
return document.createElement('custom-button') as CustomButtonElement;
};const tailwindButton = CustomButton({
type: 'submit',
className: 'flex align-left text-white bg-red-500',
});```
---
## Further Reading
- [webcomponents.org](https://www.webcomponents.org/)
- [eisenebergeffect @ Medium: Hello Web Components](https://eisenbergeffect.medium.com/hello-web-components-795ed1bd108e)
- [MDN's Web Component examples](https://github.com/mdn/web-components-examples)
- [MDN's Web API glossary](https://developer.mozilla.org/en-US/docs/Web/API)
- [MDN's Web API - HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement)
- [Building Interoperable Web Components (including React)](https://css-tricks.com/building-interoperable-web-components-react/)[Read me on github.com](https://github.com/nathanjhood/ts-web-components)
[Read me on nathanjhood.github.io](https://nathanjhood.github.io/ts-web-components)