Scripts and Events
Guidelines for using client-side JavaScript `<script>` tags and handling events in Astro.
astro
## Astro Scripts and Event Handling Guidelines
1. Purpose: Add client-side interactivity (event listeners, animations, analytics, etc.) directly within `.astro` components using standard HTML `<script>` tags.
2. Default Behavior (`<script>` tag):
- Processed & Bundled: Astro processes scripts by default. It bundles imports (local files, npm modules) and handles TypeScript.
- Module Scope: Output script uses `type="module"`. This means it's deferred (non-blocking), scoped (doesn't pollute global namespace), and runs after HTML parsing.
- Deduplication: If a component with a script is used multiple times on a page, the script itself is only included once in the final HTML output.
3. Opting Out of Processing (`is:inline`):
- Use the `is:inline` directive on the `<script>` tag (`<script is:inline>`) to prevent Astro from processing it.
- The script content is rendered _exactly_ as written into the HTML.
- Imports will _not_ work. TypeScript is _not_ processed.
- The script will be duplicated if the component is used multiple times.
- Use this for simple inline scripts or when loading external scripts via `src` that shouldn't be bundled.
- Note: Adding `type="module"` or most other attributes (except `src`) to a `<script>` tag implicitly applies `is:inline`.
4. Loading Script Files:
- Local Scripts (in `src/`): Reference using a relative path in the `src` attribute (`<script src="../scripts/my-script.ts"></script>`). Astro processes, bundles, and optimizes these.
- External/Public Scripts (in `public/` or CDN): Reference using an absolute path (for `public/`) or full URL. Must use `is:inline` (`<script is:inline src="/scripts/public-script.js"></script>`). Astro does _not_ process these.
5. Event Handling:
- Astro uses standard browser APIs. No custom event syntax (like `onClick`).
- Use `document.addEventListener` or `element.addEventListener` within a `<script>` tag to attach listeners.
- Use `document.querySelectorAll` to target multiple elements if the script is part of a reusable component.
6. Custom Elements (Web Components):
- Define custom element behavior using `class MyElement extends HTMLElement { ... }` and register with `customElements.define('my-element', MyElement)` inside a `<script>` tag.
- Wrap the component's HTML template in the custom tag (`<my-element>...</my-element>`).
- Benefits:
- Encapsulates logic and DOM querying (`this.querySelector` vs. `document.querySelector`).
- Initialization logic (`connectedCallback`) runs for _each instance_ of the element, even though the defining `<script>` only runs once per page.
- Recommended for reusable interactive components built solely with vanilla JS.
7. Passing Data from Server (Frontmatter) to Client (Script):
- Server-side variables in the `---` script are not directly accessible in client-side `<script>` tags.
- Use data-\* attributes on HTML elements to store server-side values.
```astro
---
const serverMessage = "Hello from server!";
---
<div data-message={serverMessage}>...</div>
<script>
const div = document.querySelector('div');
const clientMessage = div.dataset.message; // "Hello from server!"
console.log(clientMessage);
</script>
```
- Custom elements can access these via `this.dataset.attributeName`.
8. Interaction with UI Frameworks: If a `<script>` needs to interact with elements rendered by a UI framework component (island), consider using Custom Elements, as the framework component might not be hydrated/available when the standard script runs initially.
Reference: [Astro Scripts and Event Handling Docs](https://docs.astro.build/en/guides/client-side-scripts/)