How you'd write a reactive calculator with x-HTML in 5 mins
Published: 2021-05-24 20:25:25

In this article you won't see the millionth way of writing a calculator with the tools that are well covered by many others. Instead, I'm going to show you how to do it with much less effort in a tool you probably haven't heard of yet. And it is a big deal since it automates and abstracts away frontend web app development by the ways you haven't seen elsewhere. And yeah, the calculator is a trivial app, yet it's a good example to present a few interesting concepts.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q2sjyy0syridn2avmyq7.gif)

OK, enough of the intro, here are few steps to follow:  

1. Go to: https://ide.glue.codes.
2. Create a new project.
3. Write the below code, you can click preview to see changes as your'e typing.
4. Export it to a self-contained app based on [SolidJS](http://solidjs.com/) and JSX.

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta gc-as="navName" gc-name="Home">
  <title>Calculator</title>
</head>
<body>
  <div gc-as="layout">
    <div class="container">
      <div gc-as="slot" gc-name="content">
        
        <input-x type="number">
          <script>
            props.onChange = (e) => {
              uiSignals.numberA = parseInt(e.target.value)
            }
          </script>
        </input-x>
        
        <select-x>
          <script>
            props.onChange = (e) => {
              uiSignals.operator = e.target.value
            } 
          </script>
          <option value="+">+</option>
          <option value="-">-</option>
          <option value="*">*</option>
          <option value="/">/</option>
        </select-x>
        
        <input-x type="number">
          <script>
            props.onChange = (e) => {
              uiSignals.numberB = parseInt(e.target.value)
            }
          </script>
        </input-x>
        
        <span>=</span>
        
        <input-x type="number">
          <script>
            switch (uiSignals.operator) {
              case '-':
                props.value = uiSignals.numberA - uiSignals.numberB
                break
                
              case '*':
                props.value = uiSignals.numberA * uiSignals.numberB
                break
                
              case '/':
                props.value = uiSignals.numberA / uiSignals.numberB
                break
                
              case '+':
              default: 
                props.value = uiSignals.numberA + uiSignals.numberB
            }
            
          </script>
        </input-x>
        
      </div>
    </div>
  </div>
</body>
</html>
```

## What just happened?

Well, the above code certainly wouldn't work if you dropped it into a regular HTML file. In a traditional way, you'd need to have a script below the document and manually query for an element and then update it. It could work in a small app which you don't plan to extend. But, if you need your UI to be reactive and at the same time maintainable you'd opt for some reactive framework or library. Perhaps JSX so your UI looks like HTML but it can be interpolated with dynamic data in a declarative fashion. That can be done beautifully with [SolidJS](http://solidjs.com/) and it will diff DOM at build-time as opposed to what many other frameworks/libraries do i.e. using Virtual DOM. It's all great but wouldn't it be cool to use HTML where possible and extend it to be reactive where necessary? This is exactly what you see in the code above.

It's a combination of extended tags and UI signals to mange the local state. At [GlueCodes](https://www.glue.codes), we introduced extended tags which are named: `tagName + '-x'` and have an embedded `<script>` allowing you to access variables available in the scope where they have been placed. The scripts can assign to `props` variable to change props/attributes of the extended tag. In this case, you can see writing/reading `uiSignals` which holds some sort of observables and it'll update any props they are assigned to. What you see is a meta-framework abstracting away the signals. See [SolidJS](https://github.com/solidjs/solid/blob/main/documentation/reactivity.md#signals). 

Notice the `uiSignals` are scoped to a slot/partial they are in and an HTML tag is told to be a slot by using one of many [HTML directives](https://www.glue.codes/docs-templating-htmlDirectives.html):

```html
<div gc-as="slot" gc-name="content">
...
</div>
```

So, in addition to extended tags, you can make your HTML dynamic by using attribute directives as you would in modern web frameworks. When typing most of them you'll get notified to auto-create (if don't exist) required actions or to install a widget. The vocabulary here is simple, an attribute `[gc-as]` tells what it is and other `[gc-*]` attributes are parameters.

The above code can be split into 4 parts. An embedded `script` tag in each of the extended tag allows to modify their props e.g. register events or set a value on an input. It modifies only the props of its direct parent tag. 

1) Capturing the first number:

```html
<input-x type="number">
  <script>
    props.onChange = (e) => {
      uiSignals.numberA = parseInt(e.target.value)
    }
  </script>
</input-x>
```

2) Capturing the operator:

```html
<select-x>
  <script>
    props.onChange = (e) => {
      uiSignals.operator = e.target.value
    } 
  </script>
  <option value="+">+</option>
  <option value="-">-</option>
  <option value="*">*</option>
  <option value="/">/</option>
</select-x>
```

3) Capturing the second number:

```html
<input-x type="number">
  <script>
    props.onChange = (e) => {
      uiSignals.numberB = parseInt(e.target.value)
    }
  </script>
</input-x>
```

4) Displaying the result of equation:

```html
<input-x type="number">
  <script>
    switch (uiSignals.operator) {
      case '-':
        props.value = uiSignals.numberA - uiSignals.numberB
        break

      case '*':
        props.value = uiSignals.numberA * uiSignals.numberB
        break

      case '/':
        props.value = uiSignals.numberA / uiSignals.numberB
        break

      case '+':
      default: 
        props.value = uiSignals.numberA + uiSignals.numberB
    }

  </script>
</input-x>
```

That's it about the UI signals. There is tons of features provided by [GlueCodes Studio](https://www.glue.codes). Widgets, built-in app state management, implementation assistant and many more. The most importantly it runs in the browser and stores the project metadata and the exported [SolidJS](http://solidjs.com/) code on your hard drive!

Looking forward to see your feedback!