Scripts and Event Handling
You can add interactivity to your Astro components without using a UI framework like React, Svelte, Vue, etc. using standard HTML <script>
tags. This allows you to send JavaScript to run in the browser and add functionality to your Astro components.
Client-Side Scripts
Section titled Client-Side ScriptsScripts can be used to add event listeners, send analytics data, play animations, and everything else JavaScript can do on the web.
By default, Astro processes and bundles <script>
tags, adding support for importing npm modules, writing TypeScript, and more.
Using <script>
in Astro
Section titled Using <script> in AstroIn .astro
files, you can add client-side JavaScript by adding one (or more) <script>
tags.
In this example, adding the <Hello />
component to a page will log a message to the browser console.
Script processing
Section titled Script processingBy default, <script>
tags are processed by Astro.
- Any imports will be bundled, allowing you to import local files or Node modules.
- The processed script will be injected at where it’s declared with
type="module"
. - TypeScript is fully supported, including importing TypeScript files.
- If your component is used several times on a page, the script will only be included once.
The type="module"
attribute makes the browser treat the script as a JavaScript module. This has several performance benefits:
- Rendering is not blocked. The browser continues to process the rest of the HTML while the module script and its dependencies load.
- The browser waits for HTML to be processed before executing module scripts. You do not need to listen for the “load” event.
async
anddefer
attributes are unnecessary. Module scripts are always deferred.
The async
attribute is valuable for normal scripts because it prevents them from blocking rendering. However, module scripts already have this behavior. Adding async
to a module script will cause it to execute before the page has fully loaded. This is probably not what you want.
Opting out of processing
Section titled Opting out of processingTo prevent Astro from processing a script, add the is:inline
directive.
Astro will not process your script tags in some situations. In particular, adding type="module"
or any attribute other than src
to a <script>
tag will cause Astro to treat the tag as if it had an is:inline
directive. The same will be true when the script is written in a JSX expression.
<script>
tags.
Include JavaScript files on your page
Section titled Include JavaScript files on your pageYou may want to write your scripts as separate .js
/.ts
files or need to reference an external script on another server. You can do this by referencing these in a <script>
tag’s src
attribute.
Import local scripts
Section titled Import local scriptsWhen to use this: when your script lives inside of src/
.
Astro will build, optimize, and add these scripts to the page for you, following its script processing rules.
Load external scripts
Section titled Load external scriptsWhen to use this: when your JavaScript file lives inside of public/
or on a CDN.
To load scripts outside of your project’s src/
folder, include the is:inline
directive. This approach skips the JavaScript processing, bundling, and optimizations that are provided by Astro when you import scripts as described above.
Common script patterns
Section titled Common script patternsHandle onclick
and other events
Section titled Handle onclick and other eventsSome UI frameworks use custom syntax for event handling like onClick={...}
(React/Preact) or @click="..."
(Vue). Astro follows standard HTML more closely and does not use custom syntax for events.
Instead, you can use addEventListener
in a <script>
tag to handle user interactions.
If you have multiple <AlertButton />
components on a page, Astro will not run the script multiple times. Scripts are bundled and only included once per page. Using querySelectorAll
ensures that this script attaches the event listener to every button with the alert
class found on the page.
Web components with custom elements
Section titled Web components with custom elementsYou can create your own HTML elements with custom behavior using the Web Components standard. Defining a custom element in a .astro
component allows you to build interactive components without needing a UI framework library.
In this example, we define a new <astro-heart>
HTML element that tracks how many times you click the heart button and updates the <span>
with the latest count.
There are two advantages to using a custom element here:
-
Instead of searching the whole page using
document.querySelector()
, you can usethis.querySelector()
, which only searches within the current custom element instance. This makes it easier to work with only the children of one component instance at a time. -
Although a
<script>
only runs once, the browser will run our custom element’sconstructor()
method each time it finds<astro-heart>
on the page. This means you can safely write code for one component at a time, even if you intend to use this component multiple times on a page.
Pass frontmatter variables to scripts
Section titled Pass frontmatter variables to scriptsIn Astro components, the code in the frontmatter between the ---
fences runs on the server and is not available in the browser. To send variables from the server to the client, we need a way to store our variables and then read them when JavaScript runs in the browser.
One way to do this is to use data-*
attributes to store the value of variables in your HTML output. Scripts, including custom elements, can then read these attributes using an element’s dataset
property once your HTML loads in the browser.
In this example component, a message
prop is stored in a data-message
attribute, so the custom element can read this.dataset.message
and get the value of the prop in the browser.
Now we can use our component multiple times and be greeted by a different message for each one.
This is actually what Astro does behind the scenes when you pass props to a component written using a UI framework like React! For components with a client:*
directive, Astro creates an <astro-island>
custom element with a props
attribute that stores your server-side props in the HTML output.
Combining scripts and UI Frameworks
Section titled Combining scripts and UI FrameworksElements rendered by a UI framework may not be available yet when a <script>
tag executes. If your script also needs to handle UI framework components, using a custom element is recommended.