gg logo

gg

Documentation

Changelog

Blog

JSX

BasicsCopy link to section

JSX is an extension to JavaScript that was introduced with React, which allows us to declare which markup a component or a page should display in a way that looks and feels like HTML, while still being able to use the full power of JavaScript inside of it.

TypeScript has built-in support for JSX, which gg makes use of. In fact, the .tsx file extension that we used for page files is necessary to tell TypeScript that we want to use JSX in this file. Just using the regular .ts would not work.

Knowing the syntax of HTLM is vital in order to understand JSX. You could event call JSX HTML-in-JS. JSX in gg tries to stay as close as possible to the syntax of HTML while also giving you the maximum possible type safety.

If you know React and its JSX you have a bit of a head start. But be warned: JSX in gg is quite a bit different compared to the one you're used to.

In particular, gg uses the exact same attribute names like HTML, for example, id, class, or onclick. In React, on the other hand, attribute names reflect the DOM IDL, i.e. you have to use className instead of class or onClick instead of onclick. This has been confusing developers since the dawn of React, so gg stays true to HTML.

ElementsCopy link to section

Looking back at the pages we already created in the last guides, it is pretty obvious how to create HTML elements using JSX. The syntax is basically the one you already know from HTML.

There is one crucial difference though between JSX and HTML. In HTML there are so-called empty elements that do not contain any children and thus don't require a closing tag. The br element is an example of an empty element.

However, in JSX every element has to have a closing tag. Omitting any closing tag will result in a syntax error. That means you also have to explicitly close empty elements or regular elements without any child nodes.

1// Invalid syntax: 2<br> 3 4// Valid syntax: 5<br></br>

You can also use an abbreviation in case of elements without child nodes. Instead of writing out the closing tag, you can end the opening tag with /> instead of just >.

1// Also valid syntax: 2<br />

ExpressionsCopy link to section

The real power of JSX is that you can embed any JavaScript expression right inside your markup. Everything between two curly braces will be evaluated as JavaScript code.

The most basic example would be a JavaScript expression that is just a string.

1const markup = <p>Hello {"gg"}</p>;

As promised, you can do much more than just that!

1const markup = <p>{["Hello", "gg"].join(" ")}</p>;

You can also extract the expression into a separate variable.

1const text = ["Hello", "gg"].join(" "); 2const markup = <p>{text}</p>;

It does not stop there, the expression itself can also contain more JSX.

1const text = ( 2 <span> 3 Hello <b>gg</b> 4 </span> 5); 6const markup = <p>{text}</p>;

The expression can also be an array. You can imagine this like adding all array elements as individual expressions.

1const text = ["Hello", <b>gg</b>]; 2const markup = <p>{text}</p>;

AttributesCopy link to section

Attributes in JSX work a lot like attributes in HTML. In many cases you can just add an attribute to elements like you would in HTML.

1const headline = <h1 id="headline">Hello world</h1>;

However, we can also use expressions to define attribute values.

1const id = "headline"; 2const headline = <h1 id={id}>Hello world</h1>;

We can even pass multiple attributes to an element at once using object-spread-syntax. The keys of the spreaded object are the attribute names, the object values are the attribute values.

1const attributes = { id: "headline", lang: "en" }; 2const headline = <h1 {...attributes}>Hello world</h1>;

In the last example, we spreaded all attributes of the element. But you don't have to. You can also specify some attributes directly on the element and spread other attributes using spread syntax. There can even be overlaps. In that case, the last specified value will be taken.

1const attributes = { id: "headline", lang: "en" }; 2const headline = ( 3 <h1 {...attributes} id="other-id"> 4 Hello world 5 </h1> 6);

TypeScriptCopy link to section

Since gg is built on TypeScript, it's central that all elements and attributes in JSX are strongly typed. The types that gg uses are based on the HTML spec.

Let's shortly look at two implications. According to the spec, an img element also has to have an alt attribute. Thus if you try to create an element without it, gg will not compile the code.

1// This won't work 2const image = <img src="/logo.jpg" />; 3 4// This works 5const image = <img src="/logo.jpg" alt="Logo" />;

The second implication is around so-called enumerated attributes. In HTML there are attributes with a fixed set of possible values. gg incorporates this into the type definitions for such attributes.

A classic example of this is the input element and its type attribute. There are a handful of possible values that the HTML spec includes, like "text", "email", or"number", and gg also only allows you to pass those exact values.

Attribute typesCopy link to section

The HTML spec states different kinds of attributes that only allow certain kinds of values to be passed. The following section gives an overview of the different types of attributes.

String attributes

This is the most intuitive type of attribute. After all, in plain HTML all attributes are basically strings. Note that string attributes are the only type of attributes that don't require a JSX expression. (JSX interprets the values of such attributes as strings by default.)

Examples:

  • The id attribute for all elements
  • The href attribute for a elements
  • The src attribute for img elements

Enumerated attributes

These types of attributes only have certain string values that are considered valid. For those attributes, gg forces you to choose one of the valid values.

Examples:

  • The type attribute for input elements
  • The type attribute for button elements
  • The aria-hidden attribute for all elements

String-list attributes

Some attributes in HTML actually contain not just one value, but multiple values separated by empty spaces. gg does not type those attributes as plain strings, but as either an array of strings or as a map containing the attribute values as properties with a boolean value, indicating if the given key should be included in the attribute value or not. gg then concatenates the attribute value into one string while compiling the page to HTML.

1// Array of strings 2const markup = <p class={["red", "bold"]}>Hello world</p>; 3 4// Map with string as properties and booleans as values 5const markup2 = ( 6 <p class={{ red: true, bold: true, italic: false }}>Hello world</p> 7);

Examples:

  • The class attribute for all elements
  • The aria-labelledby attribute for all elements

Enumerated string-list attributes

At last, there are also HTML attributes that accept not just one but multiple values out of a set of valid values. As with non-constrained string-list attributes, you can either pass an array or a map as the attribute value.

Examples:

  • The role attribute for all elements
  • The rel attribute for a and link elements

Number attributes

Certain HTML attributes only accept numeric values. To pass a number as attribute values you can use a JSX expression that evaluates to a number.

1const markup = <button tabindex={-1}>Click me</button>

Examples:

  • The tabindex attribute for all elements
  • The width and height attributes for img elements
  • The min and max attributes for input elements of type "number"

Boolean attributes

Some HTML attributes don't have an actual value. They are either present or they are not. Such attributes are called boolean attributes.

There are two ways to use boolean attributes in JSX. You can either use the HTML syntax, i.e. specify the attribute without a value, or you can use an expression as the value that resolves to a boolean.

// Boolean `disabled` attribute with value `false`const enabledInput = <input />;const enabledInputX = <input disabled={false} />; // Boolean `disabled` attribute with value `true`const disabledInput = <input disabled />;const disabledInputX = <input disabled={true} />;

Examples:

  • The hidden attribute on all elements
  • The disabled attribute on input and button elements
  • The required attribute on input elements

Event handler attributes

At last, you can attach event handlers to DOM elements using so-called event handler attributes. All those attributes start with on.

In HTML you have to pass a string that will be evaluated as JavaScript on the client, once the related event is captured on the element. Since we can use JavaScript directly in JSX using expressions, gg types those elements as either a function or an array of functions. (Next to ordinary functions you can also pass set-state-actions, but we'll come to that later.)

All functions that you pass will be called in the order that you pass them, each with the captured event as the single argument.

const markup = ( <button onclick={(event) => { alert("I am an on" + event.type + " handler."); }} > Click me </button>);

Examples

  • The onclick attribute for all elements
  • The onchange attribute for all elements
  • The onmouseover attribute for all elements

GotchasCopy link to section

To conclude this guide, let's talk about some common misconceptions in gg, especially if you used React before.

At first, always remember that gg is just a compiler! That means all your code will be evaluated at build-time and not at run-time. Thus you can only use Browser-APIs like the location-API inside of event handler functions, not inside of regular JSX expressions or component functions.

Besides, you have to consider a similar constraint when it comes to the functions you pass to event handler attributes. As of today, gg does not parse this function. That means it does not know about external dependencies like variables or other functions that the event-handler-function uses. It just takes the function code and includes it unmodified in the compiled HTML. So referencing anything declared outside of the scope of the function will very likely result in an error at run-time.


Now, with deep knowledge of JSX in our minds, we can take a look at components - the building blocks of the pages of your application.


Next → Components