---
area: "Learn"
parent: "Learn"
url: "https://unpoly.com/learn/scripting"
---
<nav aria-label="Unpoly docs">[All docs](https://unpoly.com/index.md) · [Learn](https://unpoly.com/learn.md)</nav>

# Scripting

Unpoly pairs HTML elements with JavaScript behavior. Instead of running scripts once per page load, you register _compilers_ that enhance matching elements whenever they enter the page: at the initial load, and again with every fragment update.

<nav aria-label="Contents">

#### Contents

- [Enhancing elements](#enhancing-elements)
- [Attaching data to elements](#attaching-data-to-elements)
- [Rendering templates](#rendering-templates)
- [Mounting framework components](#mounting-framework-components)
- [See also](#see-also)

</nav>

## Enhancing elements {#enhancing-elements}

To enhance matching elements with JavaScript, register a compiler function with [`up.compiler()`](https://unpoly.com/api/up.compiler.md):

```js
up.compiler('.current-time', function(element) {
  element.textContent = new Date().toString()
})
```

The function is called once for each `.current-time` element, when the page first loads and when a matching fragment is rendered later. This replaces listening to `DOMContentLoaded`, which only fires for the initial page.

A compiler can return a _destructor_ function. Unpoly calls it when it removes the element, e.g. when the surrounding fragment is swapped. This keeps effects like timers or global listeners from outliving their element.

<nav aria-label="Read more">

- [More: Enhancing elements with JavaScript](https://unpoly.com/learn/enhancing-elements.md)

</nav>

## Attaching data to elements {#attaching-data-to-elements}

The server can attach structured data to an element, as [relaxed JSON](https://unpoly.com/api/relaxed-json.md) in an [`[up-data]`](https://unpoly.com/api/up-data.md) attribute:

```html
<span class="user" up-data="{ age: 31, name: 'Alice' }">Alice</span>
```

The parsed data is passed to your compiler as a second argument:

```js
up.compiler('.user', function(element, data) {
  console.log(data.name) // result: "Alice"
})
```

<nav aria-label="Read more">

- [More: Attaching data to elements](https://unpoly.com/learn/data.md)

</nav>

## Rendering templates {#rendering-templates}

The server can embed `<template>` elements into its responses, for the frontend to clone without another request. This enables instant UI like [placeholders](https://unpoly.com/learn/placeholders.md) or [optimistic rendering](https://unpoly.com/learn/optimistic-rendering.md):

```html
<a up-fragment="#tip-template">Show tip</a>

<div class="tip">Click for a tip.</div>

<template id="tip-template">
  <div class="tip">Press <kbd>?</kbd> to see all shortcuts.</div>
</template>
```

Clicking the link clones the template and swaps it into the matching `.tip` element, entirely on the client. Templates can also take [variables](https://unpoly.com/learn/templates.md#dynamic).

<nav aria-label="Read more">

- [More: Templates](https://unpoly.com/learn/templates.md)

</nav>

## Mounting framework components {#mounting-framework-components}

A compiler can mount a component from a frontend framework like React or Vue, as an _island_ within a server-rendered page:

```js
up.compiler('.color-picker', function(element, data) {
  let root = createRoot(element)
  root.render(<ColorPicker value={data.value}/>)
  return () => root.unmount()
})
```

The component mounts when its element enters the page, receives props from server data, and unmounts when the fragment around it is swapped.

<nav aria-label="Read more">

- [More: Framework islands](https://unpoly.com/learn/islands.md)

</nav>

## See also {#see-also}

To convert existing `DOMContentLoaded` scripts to compilers, see [Migrating legacy JavaScripts](https://unpoly.com/learn/legacy-scripts.md).

To control how scripts and callbacks run under a Content Security Policy, see [Script security](https://unpoly.com/learn/script-security.md).

<nav aria-label="In this chapter">

## In this chapter {#children-index-title}

- [Enhancing elements with JavaScript](https://unpoly.com/learn/enhancing-elements.md)
- [Attaching data to elements](https://unpoly.com/learn/data.md)
- [Templates](https://unpoly.com/learn/templates.md)
- [Framework islands](https://unpoly.com/learn/islands.md)
- [Migrating legacy JavaScripts](https://unpoly.com/learn/legacy-scripts.md)
- [Script security](https://unpoly.com/learn/script-security.md)

</nav>

<nav aria-label="Reading order">

- [Previous: Controlling motion](https://unpoly.com/learn/controlling-motion.md)
- [Next: Enhancing elements with JavaScript](https://unpoly.com/learn/enhancing-elements.md)

</nav>

