DEV Community

Matias Trujillo
Matias Trujillo

Posted on

More scalable applications only using forms and webcomponents

I present to you @atomico/magic-form a set of webcomponents created with AtomicoJS that centralizes form submission to build scalable applications using traditional forms.

Traditional forms? I mean the use of the <form> tag, example:

<form actio="myAction">
  <input type="name" />
  <button>submit</button>
</form>
Enter fullscreen mode Exit fullscreen mode

Now let's add some of the magic of MagicForm.

<MagicFormProvider
  actions={{
    async myAction(form: HTMLFormElement) {
      return myApi(new FormData(form));
    },
  }}
>
  <MagicForm>
    <form actio="myAction">
      <input type="name" />
      <button>submit</button>
    </form>
  </MagicForm>
</MagicFormProvider>
Enter fullscreen mode Exit fullscreen mode

In the above code we have added 2 components:

MagicFormProvider: centralizes the actions of nested MagicForms.

MagicForm: identifies the form to be observed by MagicFormProvider, this component also allows knowing the status of the sending and the return of the myAction function through the onChangeState event

The benefits of using MagicForm are:

1. Reusable Actions

Thanks to MagicFormProvider we can easily reuse the actions between forms, example:

<MagicFormProvider
  actions={{
    async myAction(form: HTMLFormElement) {
      return myApi(new FormData(form));
    },
  }}
>
  <MagicForm>
    <form actio="myAction">
      <input type="name" />
      <button>submit</button>
    </form>
  </MagicForm>
  <MagicForm>
    <form actio="myAction">
      <input type="name" />
      <button>submit</button>
    </form>
  </MagicForm>
</MagicFormProvider>;
Enter fullscreen mode Exit fullscreen mode

2. Observe the status of the form

The form submission process can be observed through the onChangeState event, this will allow you to know the submission status and the action response:

<MagicForm
  onChangeState={({ currentTarget }) => {
    console.log(currentTarget.state);
  }}
>
  <form actio="myAction">
    <input type="name" />
    <button>submit</button>
  </form>
</MagicForm>
Enter fullscreen mode Exit fullscreen mode

3. Microfrontend

If MagicFormProvider does not find the dispatched action among its actions, it will continue to bubble until the next MagicFormProvider, this allows you to have multiple islands with isolated and reusable actions, example:

<MagicFormProvider actions={{
    async login(){...}
}}>
    <MagicFormProvider actions={actionsClient}>
        <PageClient/>
    </MagicFormProvider>
    <MagicFormProvider actions={actionsAdmin}>
        <PageAdmin/>
    </MagicFormProvider>
</MagicFormProvider>
Enter fullscreen mode Exit fullscreen mode

Beautiful isn't it? but how to use it

  1. Webcomponent
  2. AtomicoJS: Atomico is a powerful library that allows you to create web components like MagicForm
  3. React and Preact

Webcomponent

<magic-form-provider>
  <magic-form>
    <form action="user">
      <input type="text" name="name" />
      <input type="text" name="email" />
      <button>Create user</button>
    </form>
  </magic-form>
</magic-form-provider>
<script>
  await customElements.whenDefined("magic-form-provider");

   document.querySelector("magic-form-provider").actions = {
     async add(form) {
       return fetch("./my-api", {
         method: "post",
         body: new FormData(form),
       }).then((res) => res.json());
     },
   };
</script>
Enter fullscreen mode Exit fullscreen mode

Atomico Js

import { MagicForm, MagicFormProvider } from "@atomico/magic-form";

function component() {
  return (
    <host>
      <MagicFormProvider
        actions={{
          async add(form) {
            return fetch("./my-api", {
              method: "post",
              body: new FormData(form),
            }).then((res) => res.json());
          },
        }}
      >
        <MagicForm>
          <form action="user">
            <input type="text" name="name" />
            <input type="text" name="email" />
            <button>Create user</button>
          </form>
        </MagicForm>
      </MagicFormProvider>
    </host>
  );
}
Enter fullscreen mode Exit fullscreen mode

React and Preact

To use this webcomponents in React or Preact you must install @atomico/react, remember that for its use in Preact you must change the module from "@atomico/magic-form/react" to "@atomico/magic-form/preact"

import { MagicForm, MagicFormProvider } from "@atomico/magic-form/react";

export function App() {
  return (
    <>
      <MagicFormProvider
        actions={{
          async add(form) {
            return fetch("./my-api", {
              method: "post",
              body: new FormData(form),
            }).then((res) => res.json());
          },
        }}
      >
        <MagicForm>
          <form action="user">
            <input type="text" name="name" />
            <input type="text" name="email" />
            <button>Create user</button>
          </form>
        </MagicForm>
      </MagicFormProvider>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

MagicForm is AtomicoJS project.

AtomicoJS? Open source project for the creation of interfaces based on webcomponents, MagicForm was created with Atomico, a library of only 3kB that will allow you to create webcomponents with a functional approach, we invite you to learn more about Atomico and its tools that will improve your experience with webcomponents.

👐 I invite you to join the Atomicojs community and learn more about our projects! 👇

Top comments (0)