Directly using document or window elements in Astro JS requires specific handling because Astro defaults to server-side rendering (SSR), and these objects (document and window) are defined in the browser environment, not available on the server-side. This means that directly using these objects at the top of a component or in server-executed code will result in errors.
To correctly use document and window in Astro, ensure that the code runs only on the client-side. Here are several methods to achieve this:
1. Using Client-Only Components
Astro allows you to specify certain components to run exclusively on the client-side. You can use the client:only directive to instruct Astro that a specific component should only be rendered on the client-side. This guarantees that any document or window objects used within this component are safe, as they won't be accessed during server-side rendering.
For example, if you have a component requiring the window object, you can implement it as follows:
jsx--- // Example.astro --- <div client:only="my-component"> <MyComponent /> </div>
2. Dynamic Import
In Astro, dynamically import modules so they load and execute only on the client-side. Within these dynamically imported modules, you can safely access document and window.
javascript--- // SomeComponent.astro import { useEffect } from 'react'; let LoadedComponent; if (typeof window !== 'undefined') { LoadedComponent = (await import('../components/ClientOnlyComponent')).default; } --- {LoadedComponent ? <LoadedComponent /> : <p>Loading...</p>}
3. Using Inline Scripts
When you need to run scripts directly on an Astro page, use the <script> tag and ensure it executes only on the client-side.
html--- // InlineScript.astro --- <script> if (typeof window !== 'undefined') { // Safely use window or document window.addEventListener('resize', () => { console.log('Window size changed!'); }); } </script>
Example
Suppose you need to adjust element sizes upon page load. You can implement this in Astro as follows:
astro--- // ResizeComponent.astro import { onMount } from 'solid-js'; function resizeHandler() { const element = document.getElementById('some-element'); if (element) { element.style.height = `${window.innerHeight}px`; } } --- <div client:only="resize"> <script> onMount(() => { window.addEventListener('resize', resizeHandler); resizeHandler(); // Initial call }); </script> <div id="some-element">Adjust me!</div> </div>
As demonstrated, using the client:only directive ensures components render only on the client-side, enabling safe access to browser objects. These methods help you effectively utilize document and window in your Astro projects while avoiding errors during server-side rendering.