src/content/docs/en/tutorial/3-components/4.mdx
import Blanks from '/components/tutorial/Blanks.astro';
import Box from '/components/tutorial/Box.astro';
import Checklist from '/components/Checklist.astro';
import MultipleChoice from '/components/tutorial/MultipleChoice.astro';
import Option from '/components/tutorial/Option.astro';
import PreCheck from '/components/tutorial/PreCheck.astro';
import { Steps } from '@astrojs/starlight/components';
Let's add a button to open and close your navigation menu on mobile screen sizes, requiring some client-side interactivity!
<PreCheck> - Create a menu component - Write a `<script>` to allow your site visitors to open and close the navigation menu - Move your JavaScript to its `.js` file </PreCheck>Create a <Menu /> component to open and close your mobile menu.
Copy the following code into your component. It creates a button that will be used to toggle the visibility of the navigation links on mobile devices. (You will add the new CSS styles to global.css later.)
---
---
<button aria-expanded="false" aria-controls="main-menu" class="menu">
Menu
</button>
Place this new <Menu /> component just before your <Navigation /> component in Header.astro.
---
import Menu from './Menu.astro';
import Navigation from './Navigation.astro';
---
<header>
<nav>
<Menu />
<Navigation />
</nav>
</header>
Add the following styles for your Menu component, including some responsive styles:
/* nav styles */
.menu {
background-color: #0d0950;
border: none;
color: #fff;
font-size: 1.2rem;
font-weight: bold;
padding: 5px 10px;
}
.nav-links {
width: 100%;
display: none;
margin: 0;
}
.nav-links a {
display: block;
text-align: center;
padding: 10px 0;
text-decoration: none;
font-size: 1.2rem;
font-weight: bold;
text-transform: uppercase;
color: #0d0950;
}
.nav-links a:hover,
.nav-links a:focus{
background-color: #ff9776;
}
:has(.menu[aria-expanded="true"]) .nav-links {
display: unset;
}
@media screen and (min-width: 636px) {
.nav-links {
margin-left: 5em;
display: block;
position: static;
width: auto;
background: none;
}
.nav-links a {
display: inline-block;
padding: 15px 20px;
}
.menu {
display: none;
}
}
Your header is not yet interactive because it can't respond to user input, like clicking on the menu to show or hide the navigation links.
Adding a <script> tag provides client-side JavaScript to "listen" for a user event and then respond accordingly.
```astro title="src/pages/index.astro" ins={2-9}
<Footer />
<script>
const menu = document.querySelector('.menu');
menu?.addEventListener('click', () => {
const isExpanded = menu.getAttribute('aria-expanded') === 'true';
menu.setAttribute('aria-expanded', `${!isExpanded}`);
});
</script>
</body>
```
2. Check your browser preview again at various sizes, and verify that you have a working navigation menu that is both responsive to screen size and responds to user input on this page. </Steps>
.js fileInstead of writing your JavaScript directly on each page, you can move the contents of your <script> tag into its own .js file in your project.
```js title="src/scripts/menu.js"
const menu = document.querySelector('.menu');
menu?.addEventListener('click', () => {
const isExpanded = menu.getAttribute('aria-expanded') === 'true';
menu.setAttribute('aria-expanded', `${!isExpanded}`);
});
```
2. Replace the contents of the <script> tag on index.astro with the following file import:
```astro title="src/pages/index.astro" ins={10} del={3-8}
<Footer />
<script>
const menu = document.querySelector('.menu');
menu?.addEventListener('click', () => {
const isExpanded = menu.getAttribute('aria-expanded') === 'true';
menu.setAttribute('aria-expanded', `${!isExpanded}`);
});
import "../scripts/menu.js";
</script>
</body>
```
3. Check your browser preview again at a smaller size and verify that the menu still opens and closes your navigation links.
Add the same <script> with import to your other two pages, about.astro and blog.astro and verify that you have a responsive, interactive header on each page.
<Footer />
<script>
import "../scripts/menu.js";
</script>
</body>
:::note[Takeaway] You had previously used some JavaScript to build parts of your site:
Those commands are all executed at build time to create static HTML for your site, and then the code is "thrown away."
The JavaScript in a <script> tag is sent to the browser, and is available to run, based on user interactions like refreshing a page or toggling an input.
:::
When does Astro run any JavaScript written in a component's frontmatter? <MultipleChoice>
<Option> Astro never runs JavaScript </Option> <Option isCorrect> at build-time </Option> <Option> When a visitor clicks a button </Option> </MultipleChoice>Optionally, Astro can send JavaScript to the browser to allow: <MultipleChoice>
<Option> users to click page links </Option> <Option> faster load times </Option> <Option isCorrect> client-side interactivity </Option> </MultipleChoice>The client-side JavaScript will be sent to a user’s browser when it is written or imported: <MultipleChoice>
<Option isCorrect> in `<script>` tags </Option> <Option> between a `.astro` file's code fences </Option> <Option> in `global.css` </Option> </MultipleChoice>