#

## Project

When richer interactivity and dynamic state are needed, a single-page application is often a better fit than a multi-page website.

The suggested project layout for single-page applications is the same as for multi-page sites, except:

/public/pages
  As there is only `index.html` there is no need for the pages folder.
/public/app
  All of the views and routes for the application are in this folder, each implemented as a web component, and registered in `index.js`.
/public/app/App.js
  As in the major frameworks, the application is bootstrapped from an App component. See the example below.

#

## Routing

Without the assistance of a server to do routing, the easiest option is hash-based routing:

- The current route is in `window.location.hash`, e.g. `#/about`.
- The route's changes are detected by listening to the Window hashchange event.
- Each web component is shown or hidden based on the active route.

This behavior can be encapsulated in a routing web component:

An example single-page vanilla application that uses this routing component:

It makes use of the template pattern to avoid showing a broken application if scripting is disabled.

Adding additional route components to the `/app` folder is left as an exercise for the reader.

### About Search Engines

The hash-based routing approach is effectively invisible to search engines. Only the initial route will be indexed. For this reason this approach is not suited to sites that have SEO concerns. Every route that must be discoverable through a search engine should use the multi-file approach explained on the Sites page.

For a more advanced but less intuitive client-side routing solution that uses `pushState`, see the article on Clean Client-side Routing.

#

## Entity encoding

A real-world application will often have complex markup in the web components, filled with variables based on user input. This creates a risk for Cross-Site Scripting. In fact, eagle-eyed readers may have noticed in the Passing Data example of the Components page that a XSS bug snuck in. By entering the following as a name, the output of `list.js` would have code injected:
`<button onclick="alert('gotcha')">oops</button>`

Go ahead and return to that page to try it ...

To solve this we need to encode dangerous HTML entities while plugging variables into HTML markup, something frameworks often do automatically in their templating layer. This `html``` literal function can be used to do this automatically in a vanilla codebase:

The reworked `list.js` that uses this:

To learn more on using this function, check the html-literal documentation.

#

## Managing state

### Where state lives

State is the source of truth of what the application should show. It is the data that gets turned into markup on the page by the application's logic.

In web frameworks state is often carefully managed so that it lives outside of the DOM, and then rendered into the DOM using a view layer. Every time the state is modified, the view layer rerenders the current view based on the new state, updating the DOM behind the scenes to match the new view. In this design the DOM is just a view on the state, but does not actually contain the state.

In vanilla web development however, state and view are merged together inside of a web component. The component carries its state in attributes and properties, making it part of the DOM, and it updates its appearance based on changes in that state in a self-contained way. In this design the DOM ends up being the owner of the state, not just a view on that state.

Take for example a simple counter:

The `<x-counter>` component carries its state in the `#count` property, it provides an API for safely changing the state with the `increment()` method, and it always updates its appearance when the state is changed using the `update()` method.

### Lifting state up

Putting state inside of web components as attributes and properties at first can seem simple, but when scaling this up to more complex hierarchies of components it quickly becomes difficult to manage. This means care must be taken to organize state across the component hierarchy in the right way.

Generally speaking, the state management principles laid out in the React documentation are sound and should be followed even for vanilla web development. Here they are once again:

1. Group related state. If you always update two or more state variables at the same time, consider merging them into a single state variable.
2. Avoid contradictions in state. When the state is structured in a way that several pieces of state may contradict and “disagree” with each other, you leave room for mistakes. Try to avoid this.
3. Avoid redundant state. If you can calculate some information from the component's attributes or properties during rendering, you should not put that information into that component's state.
4. Avoid duplication in state. When the same data is duplicated between multiple state variables, or within nested objects, it is difficult to keep them in sync. Reduce duplication when you can.
5. Avoid deeply nested state. Deeply hierarchical state is not very convenient to update. When possible, prefer to structure state in a flat way.

Let's look at these principes in action by porting the React lifting state up tutorial example application to vanilla code:

The implementation is divided across two web components: `<x-accordion>` and `<x-panel>`. The state is "lifted up" from the panels onto the accordion, so that the accordion carries the state for both panels in a single central place.

Each of the two panels is stateless. It receives its state through the `title` and `active` properties. When it is active, it shows its children (inside of a slot). When it is not active, it shows a button labeled "Show". It always shows the title.

By contrast, the accordion is where the state for the panels actually lives:

What to pay attention to:

- The accordion's `activeIndex` property carries the state, and everything else is derived from that. This property becomes the single source of truth for the application, avoiding redundant state.
- An event listener for the `show` event sent by a panel will set `activeIndex` to the right value. The property setter for `activeIndex` explicitly calls the `update()` method to bring the rest of the DOM in sync with the property's new state.

Finally, take a look at the original implementation of Accordion and Panel in React's tutorial:

Take note of how the state is organized the same across the React and vanilla implementations. The differences are in implementation details for state and rendering, not in how the application is structured.

#### Tread lightly

In vanilla web development the components become part of the DOM hierarchy, instead of existing outside of the DOM and having changes applied to it automatically by the framework. This means the application's state itself becomes part of the DOM.

Because there is no framework patching the DOM with only the parts that changed, we have to tread lightly and only update the DOM when and where that is needed. Recreating too much of the DOM after a state change risks losing state or causing performance issues. Each web component in this example renders its fixed DOM structure once in `connectedCallback()` and then updates those DOM elements in the `update()` method when the state changes.

### Passing data deeply

While passing state deep into a hierarchy by handing it from parent components to child components via attributes or properties works, it can quickly become verbose and inconvenient. This is especially the case if you have to pass those through many components in the middle which have no need for that state aside from passing it to their child components, an anti-pattern colloquially known as "prop drilling".

Again we can take inspiration from how popular frameworks like React organize state, by adapting the concept of a context. A context holds state at a high level in the component hierarchy, and it can be accessed directly from anywhere in that hierarchy. The whole concept of a context is explained in the React passing data deeply tutorial.

To understand how to apply this concept in vanilla web development let us look at the ThemeContext example from the useContext documentation page. Here is an adapted vanilla version that uses a central context to keep track of light or dark theme, toggled by a button.

In this example a special web component `<x-theme-context>` is created, whose only job is to keep track of state, provide setters to update that state, and dispatch events when the state changes.

Some key take-aways:

- The `x-theme-context` component applies the context protocol, a convention for how web components can implement a context pattern. It does this by making use of a minimal implementation of the protocol provided in `tiny-context.js`.
- The context component also uses `display: contents` to avoid impacting the layout. It exists in the DOM hierarchy, but it becomes effectively invisible.
- Instead of `useContext` every component obtains the nearest theme context by dispatching a `context-request` event, whose callback will be answered by the nearest provider higher up in the DOM that provides the asked for context. By passing `true` as the subscribe parameter the components can subscribe to updates.
- The `theme-toggle` function is also provided to the button by the context component. This mechanism can be used for dependency injection across web components.

The needs more context article does a deeper dive into the context protocol and the tiny-context implementation of it.

#### Challenge

This technique can be further extended to implement the reactive concept of reducers, by adding them as a method on a context component and updating the state through the setters, dispatching the necessary events to update the component hierarchy.

To prove your mastery of vanilla web development use the techniques you've learned to port the React documentation's example Scaling Up with Reducer and Context to vanilla code.

## Up next

Go build something vanilla!

(Or keep reading on the blog.)