Ultima revisión 31/12/2022
Cómo crear Web Components de forma usable y accesible
Para terminar el año, os mostraré cómo crear un web component desde un punto de vista más reutilizable, usable y accesible de modo sencillo y rápido. De hecho, es más rápido y pesa infinitamente menos que su equivalente en frameworks como Angular o React.
NOTA: Si no sabéis mucho sobre Web Components, siempre podéis echarle un vistazo a la web de MDN, en la url Web Components de Developer Mozilla.
class App extends HTMLElement{
constructor() {
super();
this.shadow = null;
this.name = this.constructor.name.toLocaleLowerCase();
console.log(this.name)
}
connectedCallback() {
this.shadow = this.attachShadow({ mode: "open" });
this.shadow.innerHTML = this.getStyles() + this.getView();
}
getStyles(){
if(this.name == "app" || this.name == undefined){
let link = document.createElement("link");
link.href = App.path + "app.css";
link.rel = "stylesheet";
document.querySelector("head").append(link);
return "";
} else {
return ``;
}
}
getView(){
this.getHTML(App.path + (this.name == "app" ? '': (this.name + '/')) + this.name+'.html');
return '';
}
async getHTML (path) {
let request = await fetch(path);
if (!request.ok) return;
this.shadow.innerHTML += await request.text();
}
}
App.path = document.currentScript.src.replace(document.currentScript.src
.split("/").reverse()[0], "").replace("/js", "")
App.prototype.getStyles();
Archivo app.js
En el código anterior, podemos ver cómo se ha definido una clase denominada App que tiene un método constructor, el método connectedCallback y otros tres más. El primero de ellos, el llamado getStyles(), es el que nos cargará los estilos asociados al componente que se esté invocando. El segundo, el llamado getView(), es el que nos cargará el código HTML asociado a dicho componente web y, el tercero, llamado getHTML(), es el que nos permitirá leer, en este caso, el HTML de un archivo externo.
Para que este componente funcione correctamente, deberemos crear una carpeta llamada components y, ahí, crear los archivos app.js (donde estará este código), app.css (dónde podrán estar los estilos globales para todo componente que creemos posteriormente) y app.html con el cógido que deseemos usar previamente antes de cargar cualquier componente dependiente de este componente base. No obstante, en este ejemplo no lo usaremos, por lo que lo dejaremos vacío.
Después de definir la clase, definiremos la URL base del componente App. el cuál nos servirá para crear nuevos componenetes web de una forma más rápida y sencilla. Y, por último, lo que hace el código anterior es llamar a getStyles(), que inserta el código en el HEAD de la página, aunque esto es un paso omitible.
Una vez que tengamos el direciorio creado con estos archivos, lo que haremos es crear otro subdirectorio o carpeta dentro, que en este caso llamaremos todoapp.
Dentro de la carpeta todoapp, crearemos los archivos todoapp.js, donde estará elJavaScript de nuestro Web Component dependiente del base llamada (App), todoapp.css, dónde se incorporarán los estilos propios para este componente y, todoapp.html, dónde estará el cógido HTML del actual componente.
:host, :root {
--color: 255, 255, 255;
--bg: 40, 44, 52;
--button: 252, 146, 158;
--input: 121, 182, 242;
--inverted: 0, 0, 0;
--space: 1.5em;
}
* {
box-sizing: border-box;
color: rgba(var(--color), 1);
background: rgba(var(--bg), 1);
font-family: Segoe UI, sans-serif;
font-weight: 400;
font-style: normal;
}
section {
background: rgba(var(--bg), 1);
padding: 10px;
}
h1 {
font-size: 18px;
font-weight: bold;
margin: 10px 0
}
label {
display: block;
margin-top: 10px;
}
input {
width: 100%;
display: block;
border: 1px solid rgba(var(--bg), 0.5);
background: rgba(var(--input), 1);
color: rgba(var(--inverted), 1);
padding: 5px;
margin: 5px 0 0 0;
overflow: visible;
font-family: inherit;
font-size: 100%;
line-height: 1.15;
}
[type=button], [type=reset], [type=submit], button {
-webkit-appearance: button;
margin-top: 10px;
padding: 5px 10px;
background: rgba(var(--button), 1);
color: rgba(var(--inverted), 1);
border: 1px solid rgba(var(--color), 0.5);
}
ul {
margin-top: 20px;
font-size: 16px;
color: #1a1a1a;
padding-left: 20px;
}
Archivo app.css
class TodoApp extends App {
constructor() {
super();
window.todoApp = TodoApp.prototype
}
handleSubmit(e) {
e.preventDefault();
let ul = e.target.getRootNode().querySelector("ul");
let inp = e.target.getRootNode().querySelector("input");
let li = document.createElement("li")
li.innerHTML = inp.value;
ul.append(li)
return false;
}
}
window.customElements.define("todo-app", TodoApp);
Archivo todoapp.js
/*Lo que se desee poner como estilos específicos*/
Archivo todoapp.css
<section>
<h1>Tareas pendientes</h1>
<ul></ul>
<form name="frmTodoApp" method="get" onsubmit="return todoApp.handleSubmit(event);">
<label htmlFor="new-todo">
¿Qué se necesita hacer?
</label>
<input
id="new-todo"
onChange={this.handleChange}
placeholder="Introduzca una tarea"
/>
<button>Añadir</button>
</form>
</section>
Archivo todoapp.html
Si deseáis más información Web Components y JavaScript podéis adquirir mi libro Domine JavaScript 4ª Edición, de la editorial RA-MA y disponible también en Google Books.