arrow-left
Only this pageAll pages
gitbookPowered by GitBook
triangle-exclamation
Couldn't generate the PDF for 142 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

English

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

API

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Guides

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

packages

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Atomico

A micro library inspired by React Hooks, designed and optimized for the creation of webcomponents.

import { c } from "atomico"; // 2.5kB

const MyComponent = c(
  ({name})=><host shadowDom>Hello, {name}</host>,
  {
    props: { name: String }
import { c } from "atomico"; // 2.5kB

const MyComponent = c(
  ({name})=><host shadowDom>Hello, {name}</host>,
  {
    props: { name: String }

Atomico simplifies learning, workflow and maintenance when creating webcomponents and achieves it with:

  1. Scalable and reusable interfaces: with Atomico the code is simpler and you can apply practices that facilitate the reuse of your code.

  2. Open communication: with Atomico you can communicate states by events, properties or methods.

  3. Agnostic: your custom Element will work in any web-compatible library, eg React, Vue, Svelte or Angular.

  4. Performance: Atomico has a comparative performance at Svelte levels, winning the third position in performance according to in a comparison of 55 libraries among which is React, Vue, Stencil and Lit.

hashtag
API

What can you do with Atomico?

With Atomico you can do this and more

You can create amazing webcomponentschevron-rightYou can create design systemschevron-rightYou can create web applicationschevron-rightYou can create mobile applicationschevron-rightYou can create websiteschevron-right
}
);
customElements.define("my-component", c(component));
}
);
customElements.define("my-component", c(component));
webcomponents.devarrow-up-right
dnaProps(Properties)chevron-right
puzzle-pieceVirtualDOMchevron-right
fishing-rodHookschevron-right
microscopeTestingchevron-right

You can create amazing webcomponents

Atomico makes it easy to build components with less code, better readability, and better reusability.

We invite you to discover part of the development experience you will get with Atomico:

hashtag
Create really fast webcomponents

Quick components to write since with Atomico you will require fewer lines of code to declare your webcomponents which will help you to be more productive

Fast in performance, since Atomico sends less code to the client, making your interface load quickly

hashtag
Create web components with less code

This is thanks to a functional orientation inherited from React hooks plus some internal optimization from Atomic that ease the process of shaking the tree at compile time, achieving in this way sending the client a highly optimized JS that only has what you really use

hashtag
Create webcomponents with a functional orientation

This is thanks to Atomico's reliance on React hooks syntax plus the ability to completely eliminate the need for this when using webcomponents.

hashtag
Create friendly webcomponents for React, Vue and other libraries

Atomic offers additional coverage for native behavior for React and Vue, allowing your component to be more embed-friendly, example React:

Getting started with Atomico for React users

Hi, I'm Atomico js and I bring you the React syntax for webcomponents, I think you and I get along very well 😊.

First let's say that Atomico is light since it has a size close to 3kB vs React + ReactDOM that have a size close to 60kB, now if your project is already written in React I can integrate Atomico progressively since a component created can be instantiated as a component for React thanks to @atomico/react, example:

Magical 🪄, isn't it?... well now let's speed up your Atomico learning path:

hashtag
How to declare a component?

Atomico, like React, allows a declaration of components using only functions, example:

From the example we will highlight the following differences:

  1. In Atomico you only use one import.

  2. useProp is like useState, but with the difference that useProp references the state from the webcomponent property defined in counter.props.

  3. const props allows us to create the properties of our webcomponent, these are like React's propTypes, but with a big difference they are associated with the instance and can be read and modified by referencing the node, example

Now I want to invite you to learn how to declare a style using Atomico.

hashtag
How do you declare styles using Atomico?

It is common to see the use of libraries such as Emotion or styled-components to encapsulate styles in React, but these add an additional cost, be it for performance or bundle, in Atomico there is no such cost.

hashtag
Instances, children and slots

It is normal for React to create components that you then instantiate within other components, for example:

with Atomico there are certain differences:

hashtag
1. With Atomico you can instantiate CustomElements using its constructor

The constructor in Atomic is the product of the c function and is the one you will use to register your webcomponent, example:

According to the previous example, you can instantiate MyComponent as a JSX Component, example:

This instance type allows autocompletion at the JSX level and type validation at the Typescript level.

hashtag
2. With Atomico you can instantiate components as functions as long as these are only stateless functions

This will be useful for reusing templates, but always remember stateless.

You can create design systems

Today Atomico is used in the development of design systems for various industries such as Banking, Pledge Systems, Insurance, Clinical, Government and more.

Many teams decide to use Atomico for the development of their design systems thanks to its similarity with React, which greatly facilitates the incorporation of human talent into the development of design systems.

hashtag
Why use Atomico to create design systems?

  1. Atomico offers you Storybook 7 Support with superpowers, thanks to @atomico/storybook you can create stories without the need to declare the argTypes or args since creates them for you

  2. makes it easy for you to build in NPM-friendly ESM format

  3. makes it easy for you to export your code by automatically adding the metadata so that it is optimally consumed as a package, @atomico/exports can even automatically create wrappers for React, Preact and Vue

  4. makes it easy for you to maintain a token system efficiently and sustainably

hashtag
Use cases

hashtag
IBM IX

We thank IBM IX since they have shared their experience in the development of the design system for their client Barmer, you can follow this case through Discord or Github.

import { Button } from "@formas/button/react";

function App(){
   return <>
      <h1>React App!</h1>
      <Button onClick={()=>console.log("Click!")}>
         Submit
      </Button>
   </>
}
@Atomico/storybook
@atomico/vite
@atomico/exports
@atomico/potscss-tokens
https://github.com/atomicojs/atomico/discussions/92arrow-up-right

You can create mobile applications

working on this documentation...

document.querySelector("my-counter").count = 10;
  • ReactDom.render needs a reference to mount the component, in Atomico you only need to create the my-counter tag to create a new instance of the component.

  • The <host/> tag is similar to <> </> for React, but <host/> represents the webcomponent instance and every component created with Atomico must return the host tag

  • This is only readability, but in Atomico by convention we do not use capital letters when naming our component, these are only used when creating the customElement as in line 16, since Counter is instantiable.

  • From React to Atomicochevron-right
    VirtualDOM api differenceschevron-right
    import { useState } from "react";
    import ReactDOM from 'react-dom'
    
    function Counter({initialCount}) {
      const [count, setCount] = useState(initialCount);
      return (
        <>
          Count: {count}
          <button onClick={() => setCount(initialCount)}>Reset</button>
          <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
          <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
        </>
      );
    }
    
    
    render(
      <Counter initialCount={1}/>, 
      document.querySelector("#counter")
    );
    import { c, useProp } from "atomico";
    
    const props = { count: { type: Number, value: 0 } };
    
    const Counter = c(
      () => {
        const [count, setCount] = useProp("count");
        return (
          <host>
            Count: {count}
            <button onClick={() => setCount((prevCount) => prevCount - 1)}>-</button>
            <button onClick={() => setCount((prevCount) => prevCount + 1)}>+</button>
          </host>
        );
      },
      { props }
    );
    
    customElements.define("my-counter", Counter);
    react-app.tsx
    import { Button } from "@formas/button/react";
    
    function App(){
       return <>
          <h1>React App!</h1>
          <Button onClick={()=>console.log("Click!")}>
             Submit
          </Button>
       </>
    }
    const Button = styled.a`
      /* This renders the buttons above... Edit me! */
      display: inline-block;
      border-radius: 3px;
      padding: 0.5rem 0;
      margin: 0.5rem 1rem;
      width: 11rem;
      background: transparent;
      color: white;
      border: 2px solid white;
    
      /* The GitHub button is a primary button
       * edit this to target it specifically! */
      ${props => props.primary && css`
        background: white;
        color: black;
      `}
    `
    
    render(
      <div>
        <Button
          href="https://github.com/styled-components/styled-components"
          target="_blank"
          rel="noopener"
          primary
        >
          GitHub
        </Button>
    
        <Button as={Link} href="/docs">
          Documentation
        </Button>
      </div>
    )
    import { c, css } from "atomico";
    
    const props = { primary: { type: Boolean, relfect: true } };
    
    const styles = css`
      :host {
        display: inline-block;
        border-radius: 3px;
        padding: 0.5rem 0;
        margin: 0.5rem 1rem;
        width: 11rem;
        background: transparent;
        color: white;
        border: 2px solid white;
      }
    
      :host([primary]) {
        background: white;
        color: black;
      }
    `;
    
    export const Button = c(
      () => (
        <host shadowDom>
          <slot />
        </host>
      ),
      { props, styles }
    );
    
    customElements.define("my-button", Button);
    
    function Child({children}){
        return <span>children</span>
    }
    
    function Main(){
        return <>
            <Child>text 1...</Child>
            <Child>text 2...</Child>
        </>
    }
    my-component.tsx
    import { c } from "atomico";
    
    export const MyComponent = c(() => <host>...</host>); // Constructor
    
    customElements.define("my-component", MyComponent);
    import { c } from "atomico";
    import { MyComponent } from "./my-component";
    
    export const MyApp = c(() => (
      <host>
        <MyComponent />
      </host>
    ));
    
    customElements.define("my-app", MyApp);
    function MyIcon({ size }) {
      return (
        <svg height={size} width={size}>
          <circle r="45" cx="50" cy="50" fill="red" />
        </svg>
      );
    }
    
    const MyComponent = c(() => (
      <host>
        Small <MyIcon size={"1rem"} />
        Large <MyIcon size={"2rem"} />
      </host>
    ));

    Value cycle as prop

    Atomico has a really efficient and simple type validation method, the type validation works in the following way:

    hashtag
    Cycle as attribute:

    the given value is transformed to the corresponding type, be it String, Number, Boolean, Array or Object, once transformed it is sent to the cycle as property.

    hashtag
    Cycle as property:

    evaluates if the value is of the declared type:

    • If it corresponds to the type:

      1. It is saved in props.

      2. An event is emitted (if this has been configured in the prop).

      3. It is reflected as an attribute (if this has been configured in the prop).

    Props(Properties)

    The props in Atomico are the way to associate the webcomponent properties and reactive attributes that trigger the logic or interface of the webcomponent.

    Props is the Atomico recommended way to declare visible and accessible states at the instance level of your webcomponents, with props you can:

    1. Access state via instance, example: document.querySelector("my-component").myStateProp.

    2. Dispatch events on prop value change, example: document.querySelector("my-component").addEventListener("myPropChange",console.log).

    3. Reflect attributes as prop, example: <my-component my-prop="...."> to document.querySelector("my-component").myProp.

    4. define strict input types for props.

    hashtag
    Syntax

    Any function that represents the webcomponent will be able to associate the static object props for the declaration of reactive properties and attributes, for example:

    hashtag
    Consider that:

    1. The prop names in Camel Case format will be translated to for use as an attribute to the Kebab Case format, this behavior can be modified through the "attr" property when using a structured declaration.

    2. Structured declarations require the "type" property minimally.

    3. Not all types can use the "reflect" properties.

    4. The declaration of the "value" property can vary depending on the type.

    hashtag
    Simple statements

    Simple statements allow setting just type validations.

    hashtag
    Structured declaration

    Improve the definition by adding utility declarations, allowing for example to reflect the property's value as attributes, automatically emit events or associate default values. Remember these types of declarations minimally require the use of the type property.

    hashtag
    Prop.type

    Type
    Supports reflect

    hashtag
    Prop.reflect

    If the "reflect" property is set to true, its value is reflected as an attribute of the webcomponent, this is useful for the declaration of CSS states, example:

    hashtag
    Prop.event

    It allows dispatching an automatic event before the prop value change, example:

    Where:

    • event.type: String - optional, name of the event to be emitted when the prop is changed

    • event.bubbles: Boolean - optional, indicates that the event can be listened to by containers.

    • event.detail: Any - optional, allows to attach a custom detail for the event

    The special properties of the event are the well-known Event Init, you can know more details in the .

    hashtag
    Prop.value

    Atomico allows the definition of default values of the props.

    The association of callback as value allows generating unique values for each instance of the webcomponent, this is useful with the Object and Array types since it eliminates the references between instances.

    hashtag
    Reactivity in the scope of the webcomponent

    Atomico removes the use of "this" given its functional approach, but adds the hook [useProp] (hooks / useprop.md) which allows to reference a prop for use with a functional syntax, eg:

    hashtag
    Recommended articles

    You can create websites

    Creating sites with Atomico is really easy and SEO friendly because:

    1. With Atomico you can perform SSR and SSG thanks to tools like Astro build, with Astro + Atomico you can send previously rendered components to the client, thus giving a result at the HTML level that is really friendly with search engines.

    2. Atomico being really small (3kB) your sites will load fast, especially if you only apply SSG with Atomico.

    3. Atomico not only supports SSR through Astro, you can SSR today with Atomico in Next.js, Express or any environment that supports ESM modules.

    4. (Coming soon) Yes, with Atomico soon you will be able to create blocks for Gutenberg easily

    hashtag
    We recommend for SSR or SSG based sites

    hashtag
    we recommend you for new projects

    We recommend the use of build with the @atomico/astro plugin, with this you can create sites like

    hashtag
    we recommend you for projects based on React

    Preferably we recommend + React + Atomico, but in case your project inherits the use of Next.js you can do SSR with Atomico in Next.js using .

    VirtualDOM

    Atomico's virtualDOM is designed to enhance the use of webcomponents.

    hashtag
    Syntax

    hashtag
    JSX

    Atomico supports jsx-runtime, alternatively you can import the h function to declare manual of the JSX pragma, eg:

    hashtag
    Return rule

    An important rule of Atomico's virtualDOM is that every webcomponent must return the <host/> tag since it represents the state of the webcomponent's DOM, such as:

    1. Enable the use of the shadowDOM by declaring the shadowDom property.

    2. Association of events, attributes or properties.

    3. Template of the webcomponent.

    hashtag
    Template

    hashtag
    Event Association

    Atomico considers that a property must be associated as an event if it is of the function type and begins with the prefix 'on', eg:

    hashtag
    Simple lists

    hashtag
    Lists with keys

    the key property can receive values of the type of any type that allows generating a reference to the node, eg:

    hashtag
    Node references

    A technique inherited from React, it allows obtaining the reference of the node to which the Ref object is associated through the ref property, example:

    The references must be immutable objects, to create it there is the hook that creates a reference for each instance of the webcomponent.

    hashtag
    shadowDom property

    This property allows you to declare the use of the shadowDom, eg:

    hashtag
    Method association

    You can declare a method by declaring a function in the host tag without using the prefix on in its name, eg:

    If when creating or updating the DOM it does not detect the use of the property, it will be associated as a method of this, thus allowing it to be accessed from the DOM, eg:

    To access the DOM safely wait for the resolution of the updated property created by the .

    import { c } from "atomico";
    
    const MyComponent = c(() => {
      const handlerClick = () => console.log("click!");
      return (
        <host shadowDom onclick={handlerClick}>
          <h1>content</h1>
          <slot></slot>
        </host>
      );
    });
    
    customElements.define("my-component", MyComponent);
    Astroarrow-up-right
    atomicojs.devarrow-up-right
    Astroarrow-up-right
    @atomico/react

    You can create web applications

    working on this documentation...

    Promise

    ❌

    Symbol

    ❌

    Function

    ❌

    All references to existing types in the browser(HTMLElement, Element, Node, Date, File... more than 300 😎)

    ❌

    event.cancelable: Boolean - optional, indicates that the event can be canceled by any listener

  • event.composed: Boolean - optional, allows the event to exceed the shadow-root limit

  • String

    ✔️

    Number

    ✔️

    Boolean

    ✔️

    Object

    ✔️

    Array

    ✔️

    attached documentationarrow-up-right
    Is it advisable to declare events using the props API?chevron-right
    Value cycle as propchevron-right
    useRef
    render cycle

    useRef

    Create a persistent object between renders to capture from a node from VirtualDOM

    hashtag
    Syntax

    const ref = useRef(optionalCurrent);

    hashtag
    Example

    import { useRef, useEffect, useState } from "atomico";
    
    function component() {
      const ref = useRef();
      const [message, setMessage] = useState();
      useEffect(() => {
        const { current } = ref;
        current.addEventListener("input", () => {
          if (current.validity.typeMismatch) {
            setMessage("Invalid!");
          }
          current.setCustomValidity("");
        });
      }, []);
      return (
        <host>
          <input type="email" ref={ref} />
          {message && <h1>{message}</h1>}
        </host>
      );
    }

    hashtag
    Observation

    The reference object is useful for referencing nodes between customHooks.

    import { c } from "atomico";
    
    const props = {
        // Simple statement
        value1: String,
        // Structured statement
        value2: {
          type: String,
          reflect: true,
          attr: "advaceprop",
          value: "default string",
          event: {
            type: "UpdateAdvanceProp",
            bubbles: true,
          },
        },
    };
    
    const MyComponent = c((props) => <host>{props.value1}</host>, { props });
    
    customElement.define("web-component", MyComponent);
    const props = {
      propString: String,
      propNumber: Number,
      propObject: Object,
      propArray: Array,
      propBool: Boolean,
      propCallback: Function,
    };
    // valid declaration
    const props = { myName: String };
    // valid declaration
    const props = { myName: { type: String } };
    const props = {
      checked: {
        type: Boolean,
        reflect: true,
      },
    };
    const props = {
      value: {
        type: String,
        event: {
          type: "change",
          bubbles: true,
          composed: true,
          detail: "any value",
          cancelable: true,
        },
      },
    };
    // listener
    nodeComponent.addEventListener("change", handler);
    const props = {
      valueNormal: {
        type: Number,
        value: 100,
      },
      valueObject: {
        type: Object,
        value: () => ({}),
      },
    };
    const props = { message: String };
    
    const MyComponent = c(
      () => {
        const [message, setMessage] = useProp("message");
        return (
          <host>
            Hello, {message}
            <input oninput={({ target }) => setMessage(target.value)} />
          </host>
        );
      },
      { props }
    );
    /**@jsx h*/
    import { h } from "atomico";
    import { c } from "atomico";
    
    const MyComponent = c(() => {
      // The webcomponent should always return the host tag
      return (
        <host shadowDom>
          <slot></slot>
        </host>
      );
    });
    
    customElements.define("my-component", MyComponent);
    <host onclick={() => console.log("click!")}></host>;
    <host onMyEvent={() => console.log("MyEvent!")}></host>;
    <input oninput={() => console.log("click!")} />;
    <slot onslotchange={() => console.log("update slot!")} />;
    <host>
      {[1, 2, 3].map((value) => (
        <span>{value}</span>
      ))}
    </host>
    <host>
      {[1, 2, 3].map((value) => (
        <span key={value}>{value}</span>
      ))}
    </host>
    <host>
      {listaInmutable.map((objeto) => (
        <span key={objeto}>{objeto.value}</span>
      ))}
    </host>
    const ref = useRef();
    
    <host ref={ref}></host>; // The reference will be the instance 
                             // of the custom Element
    
    <input ref={ref}/>; // The reference will be the input
    <host shadowDom></host>;
    // The use of shadow Dom is not exclusive to the host tag
    // can be used for any node that supports it
    <div shadowDom></div>;
    // Template
    <host myMethod={() => console.log("method!")}></host>;
    // Use from the DOM
    document.querySelector("my-component").myMethod();
    const myElement = new MyElement();
    
    await myElement.updated;
    
    myElement.myMethod();
  • It is sent to the update queue and subsequent rendering.

  • It does not correspond to the type: an error is created by console with the following data:

    • target: Instance of the webcomponent.

    • value: Input value.

    • type: expected type.

  • useProp

    Reactivity in the scope of the webcomponent without the use of context(this)

    useProp allows you to work with a prop(property) of the webcomponent in a similar way to useState.

    hashtag
    Syntax

    Where :

    • value: Current value of the prop.

    • setValue: Callback to update the value of the prop.

    • myProp: string, defines the name of the prop to be used by the hook.

    hashtag
    Example

    Where:

    1. useCounter is a customHook and that it can work with any property of the webcomponent of type Number.

    2. useCounter returns 2 methods increment and decrement that modify the value of the prop.

    3. useCounter can be instantiated multiple times for different properties.

    Advanced

    hashtag
    Special properties

    Property
    Type
    Effect

    shadowDom

    Boolean

    hashtag
    render

    By default, the render is configured to be used within the webcomponent by reading the return of the function, but it can be used outside of Atomico, example:

    circle-exclamation

    Render rule "The first node of the render must always be the host tag".

    hashtag
    Constructor with custom element

    This technique allows you to use any registered custom element without the need to know its tag-name for its use, example:

    Advantage :

    1. Remove leverage from tag-name

    2. Infer the types of the props and autocomplete only if you use JSX and Atomico.

    hashtag
    Constructor with DOM

    Atomico allows the use of the DOM, for this it establishes its created or recovered node as a constructor, example:

    hashtag
    Dynamic constructor

    Atomico associates the variable associated with the instance as a constructor, example:

    hashtag
    staticNode

    allows to declare a node within the scope of the function as static, this will optimize the diff process between render, achieving better performance in cases of high stress of the UI, example:

    the biggest advantage of this is that the node accesses the scope of the webcomponent

    hashtag
    cloneNode

    Allows to clone a node from the virtualDOM, example:

    The objective of this feature is to retrieve slot and use it as a template from the webcomponent.

    hashtag
    SSR hydration

    Atomico allows reusing existing DOM in the document. This is done during the webcomponent instatiation, by setting a special property in the tag to mark it for hydration.

    This can be done for shadowDom too:

    circle-info

    These code samples are not part of the standard yet, so polyfills must be used to ensure that it works in all browsers. Read more about Google Chrome's proposal here .

    Getting started with Atomico

    This guide will know the essentials to start developing webcomponents with Atomico

    Thanks for being here and getting started with Atomico. Let's talk a little about what Atomico offers today:

    1. Development agility, Atomico's functional approach simplifies code at all stages of development.

    2. Lightweight inside and out, Atomico allows you to create a component with less code and with a low dependency impact. Approximately 3kb.

    3. Really fast, Atomico has a in the browser and an agile development experience. Let's understand what a webcomponent created with Atomico looks like:

    Let's analyze the code in parts ...

    hashtag
    1.0 Imports

    What have we imported?

    1. c: Function that transforms the functional component into a standard customElement.

    2. css: Function that allows creating the CSSStyleSheet (CSS) for our component as long as it declares the shadowDom.

    hashtag
    2.0 Creating Our Web Component: Custom Element Definition

    hashtag
    2.1 Defining Component Render Function

    Our function receives all the props (Properties and Attributes) declared in props, the component function declares all the logic and template of the webcomponent. An important rule within Atomico is "📌 every component created with Atomico must always return the tag".

    hashtag
    2.2 Defining Component Properties(props) and Attributes

    Atomico detects the prop (Properties and Attributes) of the component thanks to the association of the props object, this through the use of index and value allows you to define:

    1. index: Name of the property and attribute.

    2. value: type of the prop.

    From the example we can infer that Atomico will create in our webcomponent a property and attribute called message and this can only receive values of the String type.

    hashtag
    2.3 Defining Encapsulated Styles for the Component

    Atomico detects the static styles of your component thanks to the association of the styles property:

    styles accepts individual or list CSSStyleSheet (CSS) values, the return from the css function is a standard CSSStyleSheet, so it can be shared outside of Atomico.

    hashtag
    Web Component Registration and Definition

    To create our standard customElement we will have to deliver our functional component to the c function of the Atomico module, the c function will generate as a return a customElement that can be defined or extended.

    hashtag
    Example

    const [value, setValue] = useProp(myProp);

    useReducer

    import { useProp } from "atomico";
    
    function useCounter(prop) {
      const [value, setValue] = useProp(prop);
      return {
        value,
        increment: () => setValue((value) => value + 1),
        decrement: () => setValue((value) => value - 1),
      };
    }
    
    function component() {
      const counter = useCounter("value");
      return (
        <host>
          <button onClick={counter.increment}>+</button>
          <strong>{counter.value}</strong>
          <button onClick={counter.decrement}>-</button>
        </host>
      );
    }
    
    component.props = {
      value: { type: Number, value: 0 },
    };

    Enables the use of the shadowDOM on the node.

    staticNode

    Boolean

    Render the node only once, this optimizes the update process as the node is ignored between updates.

    cloneNode

    Boolean

    clone a node of type Element

    $<name>

    any

    the $ prefix allows defining as an attribute in all cases.

    https://web.dev/declarative-shadow-dom/arrow-up-right
    import { h, render } from "atomico";
    
    
    render(
        h("host",{ style: {background:"red"} }
            h("h1",null,"Text content...")
        ),
        document.querySelector("#app")
    );
    import { h, render } from "atomico";
    
    
    render(
        <host style={{background:"red"}}>
            <h1>Text content...</h1>
        </host>,
        document.querySelector("#app")
    );
    import { html, render } from "atomico";
    
    
    render(
        html`<host style=${background:"red"}>
            <h1>Text content...</h1>
        </host>`,
        document.querySelector("#app")
    );
    good performancearrow-up-right
    https://play.atomicojs.dev/arrow-up-right
    arrow-up-right

    useHost

    Hook that creates a reference that curren is the instance of the webcomponent.

    hashtag
    Syntax

    const refHost = useHost();

    Returns the instance of the webcomponent in reference format, this reference allows to extend behaviors when creating customHooks.

    hashtag
    Example

    import { useHost, useEffect } from "atomico";
    
    function useListener(type: string, callback: (ev: Event) => void) {
      const ref = useHost();
      useEffect(() => {
        const { current } = ref;
        current.addEventListener(type, callback);
        return () => current.removeEventListener(type, callback);
      }, []);
    }

    From the example we can highlight that useListener is a customHook that allows listening to an event from the webcomponent without the need to link said event to the VirtualDOM.

    useUpdate

    Force an update, ideal for working with references

    It is normal that the state of your component depends on the references of a slot, this hook facilitates the process of observing these references without the need to associate the changes to a state.

    hashtag
    Syntax

    const update = useUpdate();

    Where:

    1. update: Callback, force component update.

    import { useProp } from "atomico";
    
    function useCounter(prop) {
      //                                 👇 type for prop
      const [value, setValue] = useProp<number>(prop);
      return {
        value,
        increment: () => setValue((value) => value + 1),
        decrement: () => setValue((value) => value - 1),
      };
    }
    
    function component() {
      const counter = useCounter("value");
      return (
        <host>
          <button onClick={counter.increment}>+</button>
          <strong>{counter.value}</strong>
          <button onClick={counter.decrement}>-</button>
        </host>
      );
    }
    
    component.props = {
      value: { type: Number, value: 0 },
    };
    // 1️⃣ We create the custom element
    const Component = c(()=><host/>);
    
    // 2️⃣ We register the custom element
    customElements.define("my-component", Component);
    
    function App(){
        return <host>
            <Component/>
        </host>
    }
    const MyComponent = c(()=>{
        const Div = useMemo(()=>document.createElement("div"));
        return <host>
            <Div style="color: black">content...</Div>
        </host>
    });
    const MyComponent = c(()=>{
        const TagName = `my-${subComponent}`;
        return <host>
            <TagName/>
        </host>
    });
    const MyComponent = c(() => (
      <host>
        <h1 staticNode onclick={console.log}>
          i am static node!
        </h1>
      </host>
    ));
    const Div = document.createElement("div");
    
    Div.innerHTML = `<h1>Div!</h1>`;
    
    const MyComponent = c(() => (
      <host>
        <Div cloneNode onclick={console.log} />
        <Div cloneNode onclick={console.log} />
        <Div cloneNode onclick={console.log} />
        <Div cloneNode onclick={console.log} />
        <Div cloneNode onclick={console.log} />
      </host>
    ));
    <my-webcomponent data-hydrate>
        <h1>I will be the title of the component</h1>
    </my-webcomponent>
    <my-webcomponent data-hydrate>
        <template shadowroot="open">
            <h2>Shadow Content</h2>
            <slot></slot>
            <style>shadow styles</style>
        </template>
        <h2>Light content</h2>
    </my-webcomponent>
    MyComponent.jsx
    // Imports
    import { c, css } from "atomico";
    
    // Creating Our Web Component: Custom Element Definition
    export const MyComponent = c(
      // Defining Component Render Function
      ({ message }) => {
        return <host shadowDom>{message}</host>;
      },
      {
        // Defining Component Properties(props) and Attributes
        props: {
          message: String,
        },
        // Defining Encapsulated Styles for the Component
        styles: css`
          :host {
            font-size: 30px;
          }
        `,
      }
    );
    
    // Web Component Registration and Definition
    customElements.define("my-component", c(component));
    MyComponent.jsx - Line: 1
    import { c, css } from "atomico";
    MyComponent.jsx - Line: 7 to 9
    // Defining Component Render Function
    ({ message }) => {
        return <host shadowDom>{message}</host>;
    }
    MyComponent.jsx - Line: 12 to 14
    // Defining Component Properties(props) and Attributes
    props: {
      message: String,
    },
    MyComponent.jsx - Line: 16 to 19
    // Defining Encapsulated Styles for the Component
    styles: css`
      :host {
        font-size: 30px;
      }
    `,
    MyComponent.jsx - Line: 25
    // Web Component Registration and Definition
    customElements.define("my-component", c(component));

    Hooks

    Improves the experience of reusing logic between webcomponents based on Atomico

    hashtag
    Hooks only for webcomponents

    usePropchevron-rightuseEventchevron-rightuseHostchevron-rightuseUpdatechevron-rightusePromisechevron-rightuseAsync and useSuspensechevron-right

    hashtag
    Hooks homogolates of React

    useStatechevron-rightuseReducerchevron-rightuseRefchevron-rightuseEffect, useLayoutEffect and useInsertionEffectchevron-rightuseMemo and useCallbackchevron-rightuseContextchevron-rightuseIdchevron-right

    hashtag
    @atomico/hooks

    Atomico today offers more Hooks external to the core, we invite you to visit with more than 50 hooks to enhance the use of webcomponents 😎

    useEffect, useLayoutEffect and useInsertionEffect

    Allows to run side effects after rendering

    hashtag
    Syntax

    useEffect(effectCallback, optionalArgumentList);

    Where :

    1. effectCallback : Function that is executed one or more times according to optionalArgumentList,effectCallback can return a function that will be executed only if effectCallback is executed again or the webcomponent is unmounted.

    2. optionalArgumentList: Array of arguments that controls the execution of effectCallback, if an argument ofoptionalArgumentList changes it will trigger that effectCallback is executed again without first cleaning the effects subscribed by the previous execution.

    hashtag
    Example

    hashtag
    useLayoutEffect

    useLayoutEffect replicates the logic of useEffect but with synchronous execution after rendering.

    hashtag
    useInsertionEffect

    useLayoutEffect replicates the logic of useEffect but with synchronous execution before rendering.

    useState

    hashtag
    Syntax

    const [state, setState] = useState(optionalInitialState);

    Where:

    1. const [state,setState] : Return of useState, the arguments allow reading and updating of the state associated with the hook instance.

      • state : Current state.

      • setState: Current status updater.

    2. useState( optionalInitialState ): Function that associates the state to the webcomponent:

      • optionalInitialState: Optional parameter that defines the initial state associated to the hook instance, If optionalInitialState is a function it will be executed in order to obtain the initial state only at the moment of the hook instance for the first time.

    hashtag
    Example

    useEvent

    Dispatch events from the webcomponent without referencing the context(this)

    hashtag
    Syntax

    Where:

    • dispatchEvent: callback, dispatches the event from the webcomponent and allows defining the detail by receiving a first parameter

    • myEvent: string, name of the event to dispatch.

    • eventInit: optional object, event configuration.

    hashtag
    Examples

    hashtag
    Event customization

    The second parameter of useEvent allows customizing the behavior of the even:

    hashtag
    Recommended articles

    const dispatchEvent = useEvent(myEvent, eventInit);
    @atomico/hooks
    @atomico/hookschevron-right

    Frequent questions

    function MyComponent() {
      const [count, setCount] = useState(0);
      return <host onclick={() => setCount(count + 1)}> {count} </host>;
    }
    How to declare events for your component at the type level for TSX?chevron-right
    import { useEvent } from "atomico";
    
    function component() {
      const dispatchEvent = useEvent("clickButton", {
        bubbles: true,
        composed: true,
      });
      return (
        <host>
          <button onclick={() => dispatchEvent()}>button</button>
        </host>
      );
    }
    import { useEvent } from "atomico";
    
    function component() {
      const dispatchEvent = useEvent("clickButton", {
        bubbles: true,
        composed: true,
      });
      return (
        <host>
          <button onclick={() => {
            const detail = "my-component"; // 👈
            dispatchEvent(detail);         // 👈
          }}>button</button>
        </host>
      )c

    useProvider

    Allows the host that instantiates this useProvider to become the context.

    This hook enables you to take control of the context from the component that instantiates useProvider, thus avoiding the need to instantiate the context node in the DOM.

    hashtag
    Example of the useProvider hook:

    import { createContext, useProvider, c } from "atomico";
    
    export const Theme = createContext({
        color: "white",
        background: "black"
    });
    
    export const App = c(()=>{
        useProvider(Theme,{
            color: "red",
            background: "yellow"
        });
        
        return <host shadowDom><slot/></host>
    });
    
    

    hashtag
    Objective

    Avoid creating an instantiable context node in the DOM.

    const listenerClickWindow = () => {
      const handlerClick = () => {
        console.log("Click window!");
      };
    
      window.addEventListener("click", handlerClick);
    
      const unlistenerClickWindow = () =>
        window.removeEventListener("click", handlerClick);
    
      return unlistenerClickWindow;
    };
    
    useEffect(listenerClickWindow, []);
    import { Host, useEvent } from "atomico";
    
    type DetailClickButton = {id: number};
    //                             👇 declaration to associate event to JSX/TSX
    function component():Host<{onclickButton: CustomEvent<DetailClickButton>}> {
    //                             👇 type for detail
      const dispatchEvent = useEvent<DetailClickButton >("clickButton", {
        bubbles: true,
        composed: true,
      });
      return (
        <host>
          <button onclick={() => {
            //            👇 Detail
            dispatchEvent({id:100});
          }}>button</button>
        </host>
      );
    }
    interface EventInit {
      // Allows the event to be dispatched upstream to the node's containers.
      bubbles?: boolean;
      // Allows the event to traverse the shadowDOM event capture.
      composed?: boolean;
      // Allows the event to be canceled.
      cancelable?: boolean;
      // Allows customizing the event builder, ideal for event instance-based communication.
      base?: Event | CustomEvent;
    }

    useId

    useId is a Atomico Hook for generating unique IDs that can be passed to accessibility attributes.

    hashtag
    Syntax

    import { useId } from "atomico";
    
    const stringId = useId();

    hashtag
    Example

    Use ID generate a unique ID for each component, this id can be useful for referencing CSS selectors or creating names for inputs that only the component knows about.

    useContext

    Since version Atomico@1.62.0 has introduced a context api as part of the core.

    With the new contexts API you will be able to easily communicate components without the need to handle events, by default the communication is top down, but through it you can share anything as long as it is defined as an object.

    Atomico's api is similar to React's Context api, let's explore the behavior of Atomico's context api:

    hashtag
    createContext

    create a custom Element as a context, this will serve to synchronize all the components nested within it, you must always remember to declare the tagname of this customElement, example

    hashtag
    useContext

    It allows to consume the return of createContext, let's go back to the previous example and suppose that we want to consume the customElement Theme created by createContext, the code for this would be the following:

    In this way useContext captures the value of the parent component or reuses the value given by default to createContext.

    hashtag
    Custom context values

    By setting the value prop on the context, you can pass custom values down the sub-tree:

    circle-info

    It is highly recommended to always use custom properties to expose the appearance configuration of your component at the static CSS level, since useContext is designed to share information between components in a unidirectional way.

    hashtag
    When to use the Context API?

    It is ideal to always prioritize a conversation between parent and child through events or props api, but sometimes the depth of the DOM makes this process difficult, for this the context api has been introduced. To remove DOM depth limitations and ensure synchronization based on a unique identifier, some ideal cases to solve with the context api are:

    1. Synchronize states or private methods between components.

    2. Share a value or states inherited from the parent regardless of DOM depth.

    Testing

    We recommend the @web/test-runnerarrow-up-right tool, if your project was created with the command npm init @atomico the test environment will be preconfigured, you can see this pre-configuration at https://github.com/atomicojs/base/tree/2-startedarrow-up-right.

    Render cyclechevron-rightatomico/test-domchevron-rightatomico/test-hookschevron-right

    hashtag
    Advanced (Documentation in progress)

    To scale the test environment you can complement with tools such as:

    1. : allows you to automate interactions and evaluate interactions of your interface.

    2. : Allows you to evaluate the appearance changes of your component or application between versions.

    useAsync and useSuspense

    suspend the execution of a render until the resolution of an asynchronous process

    hashtag
    useAsync

    with a similar approach to React's use hook, but with scope approach.

    scope approach? yes, this hook seeks to resolve a promise from a callback return, this allows you to regenerate the promise according to the scope, example:

    import { useAsync } from "atomico";
    
    const getUser = (userId) => fetch(`users/${userId}`).then((res) => res.json());
    
    function component
    
    import { Props, useAsync } from "atomico";
    
    const getUser = (userId: number): Promise<{ name: string }> =>
      fetch(`users/${userId}
    

    where:

    • getUser: async callback.

    • [ userId ]: arguments that if changed regenerate the promise.

    • user : promise return

    Like useEffect, the promise will be executed every time the arguments to the second parameter of useAsync change.

    circle-exclamation

    Rendering will be suspended until the promise is resolved or rejected, the resolution of the promises can be observed with useSuspense

    hashtag
    useSuspense

    allows to listen to all useAsync executions nested in the component, example:

    useMemo and useCallback

    hashtag
    Syntax

    const memoValue = useMemo(callback, optionalArgumentList);

    Where :

    1. memoValue : Return memorized by useMemo.

    2. callback: Function that is executed one or more times according to optionalArgumentList.

    3. optionalArgumentList: Array of arguments that controls the execution of callback, if an argument of optionalArgumentList changes it will trigger that callback is executed again.

    hashtag
    useCallback

    Hook that allows you to memorize a callback so that it keeps its scope

    Where:

    1. memoCallback : Return memorized by useCallback.

    useAbortController

    Atomico now introduces a new hook called useAbortController, which allows aborting the execution of asynchronous calls, example:

    The idea is to create an instance of AbortController every time the hook's parameters change. Each parameter change will abort the previously generated controller, thus cancelling any subscribed promises.

    hashtag
    Example

    The significant advantage of using useAbortController is the automatic cancellation of asynchronous processes that depend on it when modifying the arguments provided to useAbortController (similar to useEffect).

    usePromise

    Easily observe asynchronous processes

    The purpose of this hook is to facilitate the consumption of promises.

    hashtag
    Syntax

    where:

    • callback : asynchronous function.

    import { createContext } from "atomico";
    
    export const Theme = createContext({
        color: "white",
        background: "black"
    });
    
    customElements.define( "my-theme", Theme  );