#<script> vars
16 messages · Page 1 of 1 (latest)
Hi @hollow root. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
Passing Frontmatter Variables to <script>
Since frontmatter runs on the server and is not available in the browser, you need a workaround to pass variables to client-side <script> tags. The recommended approach is using data-* attributes.
Recommended: data-* attributes
Store your frontmatter variable as a data-* attribute on an HTML element, then read it in your script via dataset:
---
const { message = 'Welcome, world!' } = Astro.props;
---
<astro-greet data-message={message}>
<button>Say hi!</button>
</astro-greet>
<script>
class AstroGreet extends HTMLElement {
connectedCallback() {
const message = this.dataset.message;
const button = this.querySelector('button');
button.addEventListener('click', () => {
alert(message);
});
}
}
customElements.define('astro-greet', AstroGreet);
</script>
This approach works well when the component is used multiple times with different values. [Pass variables to scripts]
Alternative: define:vars (with caveats)
You can use the define:vars directive to pass variables directly:
---
const message = "Astro is awesome!";
---
<script define:vars={{ message }}>
alert(message);
</script>
⚠️ Caution: Using
define:varson a<script>impliesis:inline, meaning the script won't be bundled and will be inlined into the HTML. This also means the script reruns for every instance of the component, which may not be desirable.
In summary: Prefer the data-* attribute pattern for scripts, and reserve define:vars for <style> tags where it works without the bundling limitation.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@hollow root Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@solid oar Why can't I just define a var at the top to be bundled into script at the bottom?
Let me check the knowledge base for you again. One moment! :books:
The core reason is that frontmatter runs on the server at build/request time, while <script> tags run in the browser. They are two completely separate execution environments — the frontmatter code is stripped out entirely before the page reaches the browser, so there's no shared scope between them. [Astro components]
Additionally, Astro processes and bundles <script> tags independently — a script may be deduplicated and included only once on a page even if the component is used multiple times. If a variable from frontmatter were simply injected at the top of a bundled script, it would break this model since each instance of the component could have a different value for that variable. [define:vars directive]
This is exactly why define:vars forces is:inline on <script> tags — it has to opt out of bundling so the script can re-run with each component instance's specific values.
The data-* attribute pattern sidesteps all of this cleanly: the value is baked into the HTML (which the server can control), and the single bundled script reads it at runtime from the DOM. [Pass variables to scripts]
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@hollow root Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@solid oar So I can't put my constants into a separate file to be used in a <script> ?
Let me check the knowledge base for you again. One moment! :books:
You actually can import from a separate file in a <script> tag — but the constants need to be defined in a regular .js/.ts file in your src/ folder, not sourced from your frontmatter.
<!-- my-component.astro -->
<script>
import { MY_CONSTANT } from '../constants/myConstants.js';
console.log(MY_CONSTANT);
</script>
Astro will process, bundle, and optimize that import automatically. [Script processing]
You can also import an entire .js/.ts script file directly:
<script src="../scripts/my-script.js"></script>
What you can't do is share constants that are defined in the frontmatter (---) of an .astro file, since that code only runs on the server and is never available in the browser. If you need a constant in both places, the solution is to define it in a standalone .js/.ts file and import it in both your frontmatter and your <script> tag independently.
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
@hollow root Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@solid oar does that mean I can import functions too and they will be bundled?
Let me check the knowledge base for you again. One moment! :books:
Yes! The knowledge sources confirm that Astro's script processing supports importing from local files and npm packages, and they will all be bundled together. [Script processing]
So you can do things like:
<script>
// Import a function from a local file
import { myFunction } from '../utils/helpers.js';
// Import from an npm package
import confetti from 'canvas-confetti';
myFunction();
confetti();
</script>
Astro will:
- Bundle all the imports together
- Deduplicate the script if the component is used multiple times on a page
- Optimize the output
- Support TypeScript out of the box