Add a Bilingual Grammar Explorer
Build an accessible Japanese grammar explorer with dependent dropdowns.
Introduction
30 Second Summary
Knowing what a Japanese word means is only the first step. Its useful form changes with the word category, the time being described, and the level of politeness.
In this project, you will add a bilingual grammar explorer beside your existing Japanese vocabulary quiz. Each category reveals its own Japanese forms alongside careful English comparisons.
What You'll Build
Each category and form selection reveals Japanese examples beside English guidance while your original three-mode quiz remains available.
By the end of this project, you'll have:
- A dependent Form dropdown that changes when you select Noun, Verb, Adjective, or Adverb from the Category control.
- A bilingual grammar reference that displays noun predicate states, five verb study forms, eight adjective combinations, and a base-only adverb state.
- A responsive and keyboard-friendly explorer that identifies い-adjectives separately from な-adjectives and announces result counts through a polite live region.
- Secret Mission: Add a third dropdown that filters verb examples by Group 1, Group 2, or Group 3.
Are there any prerequisites?
This follow-on project assumes you completed the Three-Mode Japanese Vocabulary Quiz on Windows. That project provides the existing quiz plus your Visual Studio Code and Microsoft Edge setup.
Before We Start
This step is your moment to commit to building an accurate bilingual grammar reference before the hands-on work begins. Your explorer will give nouns, verbs, adjectives, and adverbs their own appropriate form choices while keeping the existing quiz unchanged.
Set Up the Grammar Explorer
The existing quiz already works as a three-mode vocabulary tool. This step protects that baseline while you prepare a separate home for grammar.
Visual Studio Code gives you a safe place to create the new files. Microsoft Edge proves that the explorer opens independently from the quiz.
In this step, get ready to:
- Confirm that the Windows tools are ready.
- Create the isolated grammar-explorer file structure.
- Open the starter explorer with its title visible.
Verify the starting point
Checking the tools first separates installation problems from project problems. Checking the original quiz gives you proof that this extension leaves it intact.
- Press the Windows key to open Windows search.
- Type Visual Studio Code into the search box.
- Confirm that Visual Studio Code appears in the results.
- Press the Windows key again.
- Type Microsoft Edge into the search box.
- Confirm that Microsoft Edge appears in the results.
✔️ Both tools are available
Your editor and browser are ready. Continue with the original quiz check below.
ⓧ A tool is missing
Install only the application that is missing. Use its official Windows instructions so the rest of the project follows the expected workflow.
- Install Visual Studio Code by following the official Windows setup guide.
- Install Microsoft Edge from the official Microsoft Edge download page.
- Repeat the Windows search check after the installation finishes.
Still missing an application?
Restart Windows if the installed application does not appear in search.
Get help checking the installation: Why is the application missing after installation?.
- Press the Windows key to open Windows search.
- Type Visual Studio Code into the search box.
- Select Visual Studio Code from the results.
- Use the folder picker to select the existing japanese-vocab-quiz folder.
- Press the Windows key again.
- Type Microsoft Edge into the search box.
- Select Microsoft Edge from the results.
Why Check the Quiz First?
The original quiz is your working baseline. Opening it before you create anything gives you a clear comparison point for the separate explorer.
- Select the folder icon on the Windows taskbar to open the file browser.
- Navigate to the location containing the japanese-vocab-quiz folder.
- Drag japanese-vocab-quiz/index.html into the Microsoft Edge window.
You'll see the existing three-mode quiz page. That check locks in a working baseline before the new component touches the screen.
Original Quiz Not Opening?
Confirm that you dragged the existing japanese-vocab-quiz/index.html file into Microsoft Edge. Keep the quiz files unchanged while you check the path.
Get help locating the correct file: Why is my existing quiz not opening in Microsoft Edge?.
Create the isolated file structure
The new subfolder keeps the grammar explorer beside the original quiz files. Each feature gets its own entry page.
- Switch back to Visual Studio Code.
- Select the japanese-vocab-quiz folder in the file sidebar.
- Use the new-folder button at the top of the file sidebar to create grammar-explorer.
You'll see grammar-explorer nested inside japanese-vocab-quiz.
- Select the new grammar-explorer folder in the file sidebar.
- Use the new-file button to create index.html inside grammar-explorer.
- Use the new-file button to create styles.css inside grammar-explorer.
You'll see index.html plus styles.css beneath the new folder.
- Use the new-file button to create script.js inside grammar-explorer.
You'll now see all three starter files together. The original quiz files remain outside the new subfolder.
Files in the Wrong Folder?
Move any misplaced file into grammar-explorer using the Visual Studio Code file sidebar.
Get help checking the structure: How should my grammar explorer files be arranged?.
Create the starter page
HTML provides the visible title. CSS supplies the first page-wide font rule.
The JavaScript file starts empty. Linking it now prepares the page for the dependent dropdown behavior you add later.
- Select grammar-explorer/index.html in the Visual Studio Code file sidebar.
- Replace its contents by pasting this code:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bilingual Form Explorer</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Bilingual Form Explorer</h1>
<script src="script.js"></script>
</body>
</html>
What Does This HTML Do?
- The document metadata prepares the browser to display the page correctly.
- The stylesheet link connects styles.css from the same folder.
- The heading creates the first visible result.
- The script element connects script.js for later behavior.
- Save grammar-explorer/index.html.
- Switch back to the Windows file browser.
- Drag grammar-explorer/index.html into the Microsoft Edge window.
You'll see “Bilingual Form Explorer” as the page heading. Your isolated page now opens independently from the original quiz.
Heading Not Visible?
Confirm that Microsoft Edge opened the index.html file inside grammar-explorer.
Get help checking the starter page: Why is my explorer heading missing?.
- Select grammar-explorer/styles.css in the Visual Studio Code file sidebar.
- Add the starter font rule by pasting this code:
body {
font-family: "Segoe UI", sans-serif;
}
What Does This CSS Do?
The body rule applies the font stack across the page. The browser uses the fallback when the first font is unavailable.
- Save grammar-explorer/styles.css.
- Refresh the explorer page in Microsoft Edge.
You'll see the same title in the new page-wide font. This visible change confirms that styles.css is linked correctly.
Font Style Not Changing?
Confirm that styles.css sits beside index.html inside grammar-explorer.
Get help tracing the stylesheet: Why is my explorer stylesheet not loading?.
✔️ Awesome, I've Got Everything
Your isolated three-file starter is complete. Save every open file before the final check.
ⓧ I'd Like to Double Check the Full Code
Compare your starter files with these complete versions.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bilingual Form Explorer</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Bilingual Form Explorer</h1>
<script src="script.js"></script>
</body>
</html>
What Should Match in the HTML?
The file contains one visible heading. It links the stylesheet plus the script file from the same folder.
body {
font-family: "Segoe UI", sans-serif;
}
What Should Match in the CSS?
The stylesheet contains one body rule with the complete font stack.
The grammar-explorer/script.js file should contain no code. Its empty state is the complete starter artifact for this step.
Before you refresh, do you expect the isolated page to keep its title without changing the original quiz?
- Refresh grammar-explorer/index.html in Microsoft Edge.
You'll see “Bilingual Form Explorer” on the page. The original three-mode quiz remains available in the parent folder.
Your explorer now has a safe home beside the original quiz. Next, you'll turn this starter into its first category bar.
Build the First Category Bar
Your explorer now has its own page in Microsoft Edge. The original quiz remains available beside it.
This first pass gives every category one shared form list. Testing that model will reveal whether the categories belong together.
In this step, get ready to:
- Build a semantic header with labeled category controls.
- Style the category bar as a sticky toolbar.
- Test the shared Form list against a different category.
Build the semantic category bar
Visible labels help learners understand each control before they interact with it. Native form controls also provide familiar keyboard behavior in the browser.
- Switch back to Visual Studio Code from earlier.
- Select grammar-explorer/index.html in the Explorer sidebar.
- Find the existing <h1>Bilingual Form Explorer</h1> line.
- Replace that line with this semantic header:
<header class="hero">
<p class="eyebrow">English + Japanese</p>
<h1>Bilingual Form Explorer</h1>
<p>Choose a word category, then choose the form you want to inspect.</p>
</header>
What does this HTML do?
- The header element identifies the page introduction.
- The eyebrow class gives the bilingual context its own styling hook.
- The final paragraph tells learners how the two controls will work.
- Save grammar-explorer/index.html.
- Return to the explorer page in Microsoft Edge.
- Refresh the page.
You should see English + Japanese above the title. You should also see a short instruction below it.
Header still looks unchanged?
Confirm that you edited grammar-explorer/index.html inside the grammar-explorer subfolder. Refresh the explorer tab after saving the file.
Ask for help with the header change.
The main interface needs two labeled dropdowns in reading order. The Form dropdown follows Category so its choices can respond to Category in the next step.
- Place the complete first-pass interface below the closing </header> tag by adding this code:
<main>
<section class="toolbar" aria-labelledby="filters-heading">
<h2 id="filters-heading">Grammar filters</h2>
<div class="controls">
<div class="field">
<label for="category-select">Category</label>
<select id="category-select">
<option value="noun" selected>Noun</option>
<option value="verb">Verb</option>
<option value="adjective">Adjective</option>
<option value="adverb">Adverb</option>
</select>
</div>
<div class="field">
<label for="form-select">Form</label>
<select id="form-select">
<option>Affirmative (non-past)</option>
<option>Past affirmative</option>
<option>Negative (non-past)</option>
<option>Past negative</option>
</select>
</div>
</div>
</section>
<section class="results">
<article class="card">Choose a category to inspect grammar forms.</article>
</section>
</main>
How is the interface structured?
- The toolbar section groups the controls under the Grammar filters heading.
- Each label points to its matching select through the same identifier.
- The Category control offers Noun, Verb, Adjective, or Adverb.
- The Form control temporarily contains four noun-oriented choices for every category.
- The card article provides a visible placeholder for future grammar results.
- Save grammar-explorer/index.html.
- Refresh the explorer page in Microsoft Edge.
You should see Category above the first dropdown. You should see Form above the second dropdown.
A placeholder card should appear below the controls with the text Choose a category to inspect grammar forms.
Controls or card missing?
Check that the new main element sits after </header>. Confirm that it remains above the existing script element.
Ask for help checking the explorer HTML.
✔️ Awesome, I've got everything!
Great. Your page now has the complete semantic structure for the first category bar.
ⓧ I'd like to double check the full code
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bilingual Form Explorer</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="hero">
<p class="eyebrow">English + Japanese</p>
<h1>Bilingual Form Explorer</h1>
<p>Choose a word category, then choose the form you want to inspect.</p>
</header>
<main>
<section class="toolbar" aria-labelledby="filters-heading">
<h2 id="filters-heading">Grammar filters</h2>
<div class="controls">
<div class="field">
<label for="category-select">Category</label>
<select id="category-select">
<option value="noun" selected>Noun</option>
<option value="verb">Verb</option>
<option value="adjective">Adjective</option>
<option value="adverb">Adverb</option>
</select>
</div>
<div class="field">
<label for="form-select">Form</label>
<select id="form-select">
<option>Affirmative (non-past)</option>
<option>Past affirmative</option>
<option>Negative (non-past)</option>
<option>Past negative</option>
</select>
</div>
</div>
</section>
<section class="results">
<article class="card">Choose a category to inspect grammar forms.</article>
</section>
</main>
<script src="script.js"></script>
</body>
</html>
How to use this reference
Compare this file with your saved grammar-explorer/index.html. Check the nesting around the header, main interface, controls, results section, or script element.
Style the toolbar and card
The page structure is now visible. CSS will turn it into a compact explorer with a sticky control area.
- Select grammar-explorer/styles.css in the Explorer sidebar.
- Select the existing body rule.
- Replace that rule with this page foundation:
:root {
font-family: "Segoe UI", sans-serif;
color: #172033;
background: #f4f7fb;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.hero,
main {
width: min(960px, calc(100% - 32px));
margin-inline: auto;
}
.hero {
padding: 40px 0 24px;
}
What does the foundation style?
- The :root rule defines the page font, text color, or background.
- The universal selector makes element dimensions include their borders or padding.
- The shared width keeps the header or main content centered.
- The .hero padding gives the page introduction breathing room.
- Save grammar-explorer/styles.css.
- Refresh the explorer page.
You should see a pale page background. The header content should sit inside a centered column.
Page still has the old spacing?
Confirm that index.html still links to styles.css. Check that each CSS rule has matching opening or closing braces.
Ask for help checking the foundation styles.
The control bar needs to remain available as the results area grows. A sticky position keeps it anchored near the top during scrolling.
- Add the toolbar styles below the .hero rule:
.toolbar {
position: sticky;
top: 0;
padding: 18px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: #ffffff;
}
.controls {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 14px;
}
.field {
display: grid;
gap: 6px;
}
select {
min-height: 44px;
padding: 9px 12px;
}
How does the toolbar work?
- The sticky position keeps the toolbar at the top of its scrolling area.
- The .controls grid creates flexible columns for the two fields.
- Each .field stacks its visible label above its dropdown.
- The minimum height gives each dropdown a larger interaction area.
- Save grammar-explorer/styles.css.
- Refresh the explorer page.
You should see the two controls inside a white rounded toolbar. The controls should form flexible columns when space allows.
Toolbar styles not appearing?
Check that the HTML uses class="toolbar" on the control section. Confirm that both field wrappers use class="field".
Ask for help matching the CSS classes.
The placeholder result needs its own visual boundary. A card makes the future grammar output distinct from the controls.
- Add the card styles below the select rule:
.card {
margin-top: 28px;
padding: 20px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: #ffffff;
}
What does the card style do?
- The top margin separates the result from the toolbar.
- The padding keeps the placeholder text away from the card edges.
- The border, rounded corners, or white background make the result area visible.
- Save grammar-explorer/styles.css.
- Refresh the explorer page.
You should see the placeholder text inside a white rounded card below the toolbar.
Placeholder still looks like plain text?
Confirm that the placeholder article uses class="card". Check that the .card rule appears outside the preceding select rule.
Ask for help with the card styling.
✔️ Awesome, I've got everything!
Your toolbar and placeholder card now have the complete starter styling.
ⓧ I'd like to double check the full code
:root {
font-family: "Segoe UI", sans-serif;
color: #172033;
background: #f4f7fb;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.hero,
main {
width: min(960px, calc(100% - 32px));
margin-inline: auto;
}
.hero {
padding: 40px 0 24px;
}
.toolbar {
position: sticky;
top: 0;
padding: 18px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: #ffffff;
}
.controls {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 14px;
}
.field {
display: grid;
gap: 6px;
}
select {
min-height: 44px;
padding: 9px 12px;
}
.card {
margin-top: 28px;
padding: 20px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: #ffffff;
}
How to use this reference
Compare this file with your saved grammar-explorer/styles.css. Check the order or closing brace of each selector block.
Test the shared form list
A JavaScript change listener can read the values selected in both controls. This first listener records the current pair whenever Category changes.
- Select grammar-explorer/script.js in the Explorer sidebar.
- Add the selection listener with this code:
const categorySelect = document.getElementById("category-select");
const formSelect = document.getElementById("form-select");
categorySelect.addEventListener("change", () => {
console.log(categorySelect.value, formSelect.value);
});
What does this listener do?
- The categorySelect constant stores the Category dropdown.
- The formSelect constant stores the Form dropdown.
- The change listener runs whenever the selected Category changes.
- The selected values are recorded together so you can inspect the current pair.
- Save grammar-explorer/script.js.
Before you test it, pause on this question: which Form choices will remain after Category changes to Verb.
- Return to the explorer page in Microsoft Edge.
- Refresh the page.
- Confirm that Category starts on Noun.
- Open the Form dropdown.
- Select Verb from Category.
- Open the Form dropdown again.
You will still see noun-oriented choices such as Past negative. The shared list has now fallen short in the exact place this test was designed to expose.
Why does the mismatch matter?
Each category needs its own set of study forms. A category-specific data model will let the second dropdown rebuild its choices after Category changes.
Form choices disappeared?
Confirm that all four Form options remain inside <select id="form-select">. Check that Category and Form use different identifiers.
Ask for help checking the shared-list prototype.
✔️ Awesome, I've got everything!
Your first-pass listener is saved. The shared Form list remains visible after Category changes.
ⓧ I'd like to double check the full code
const categorySelect = document.getElementById("category-select");
const formSelect = document.getElementById("form-select");
categorySelect.addEventListener("change", () => {
console.log(categorySelect.value, formSelect.value);
});
How to use this reference
Compare this file with your saved grammar-explorer/script.js. Pay close attention to the two control identifiers or the change event name.
Your first category bar is visible, styled, and ready for interaction. Next, you will replace the shared choices with forms that fit each category.
Give Each Category the Right Forms
Your first category bar exposed the problem clearly. The Form dropdown keeps showing noun choices after you select another category.
Each category follows different grammar rules. In this step, a dependent dropdown gives nouns, verbs, adjectives, and adverbs their own accurate form lists.
In this step, get ready to:
- Prepare the page for options generated by JavaScript.
- Model a separate set of forms for each word category.
- Rebuild the Form dropdown whenever the Category selection changes.
Prepare the dynamic page areas
The page currently hardcodes four noun options inside its HTML. Dynamic options need an empty Form control that JavaScript can rebuild.
- Switch back to grammar-explorer/styles.css in Visual Studio Code.
- Find the existing .card rule.
- Replace that rule with the card container styles below:
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
padding: 28px 0;
}
.card {
padding: 20px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: #ffffff;
}
What does this CSS do?
- The .cards grid prepares the result area for multiple grammar cards.
- The responsive columns give each future card at least 240px of space.
- The .card rule preserves the border and background for each result.
- Save grammar-explorer/styles.css.
- Refresh the explorer in Microsoft Edge.
You should see the placeholder card move directly below the toolbar because its old top margin is gone.
Does the placeholder card still have a large gap?
Check that you replaced the old .card rule. A second copy of that rule may keep the old margin active.
Ask for help checking the stylesheet rules.
The result region also needs named targets for category guidance and generated cards. These elements give JavaScript safe places to update through textContent.
- Switch back to grammar-explorer/index.html.
- Find the <div class="field"> containing the form-select control.
- Replace that field through the closing Results section with the following HTML:
<div class="field">
<label for="form-select">Form</label>
<select id="form-select"></select>
</div>
</div>
<p id="form-help" class="form-help"></p>
</section>
<section class="results">
<div id="cards" class="cards"></div>
</section>
What does this HTML change?
- The empty form-select leaves its options under JavaScript control.
- The form-help paragraph provides category-specific guidance.
- The cards container replaces the static placeholder card with a dynamic result area.
- Save grammar-explorer/index.html.
- Refresh the explorer in Microsoft Edge.
You should see an empty Form dropdown. The old placeholder card should also be gone.
Still seeing the old options or card?
Confirm that the form-select element has no option elements inside it. Check that the Results section contains the cards container.
Ask for help comparing the new HTML with the expected structure.
Model the category-specific forms
A data object keeps the visible option labels separate from the dropdown-building logic. Each category becomes a key whose value is its own list of forms.
Why use category-specific data?
Nouns use four predicate states. The requested verb list contains five study forms.
Adjectives use eight plain and polite combinations. Adverbs remain base-only because sentence tense belongs to the verb.
- Switch back to grammar-explorer/script.js.
- Find the first two const declarations.
- Replace those declarations with the four element references below:
const categorySelect = document.getElementById("category-select");
const formSelect = document.getElementById("form-select");
const formHelp = document.getElementById("form-help");
const cards = document.getElementById("cards");
What do these references provide?
- The first two constants keep access to the Category and Form controls.
- The formHelp reference points to the category guidance paragraph.
- The cards reference points to the dynamic result container.
- Add the category form data immediately below those declarations by copying this code:
const formOptions = {
noun: [
{ value: "affirmative", label: "Affirmative (non-past)" },
{ value: "past", label: "Past affirmative" },
{ value: "negative", label: "Negative (non-past)" },
{ value: "pastNegative", label: "Past negative" },
],
verb: [
{ value: "dictionary", label: "Dictionary / plain non-past" },
{ value: "masu", label: "ます-form (polite non-past)" },
{ value: "te", label: "て-form" },
{ value: "ta", label: "た-form (plain past)" },
{ value: "nai", label: "ない-form (plain negative)" },
],
adjective: [
{ value: "plainPresent", label: "Plain non-past affirmative" },
{ value: "plainPast", label: "Plain past affirmative" },
{ value: "politePresent", label: "Polite non-past affirmative" },
{ value: "politePast", label: "Polite past affirmative" },
{ value: "plainNegative", label: "Plain non-past negative" },
{ value: "politeNegative", label: "Polite non-past negative" },
{ value: "plainPastNegative", label: "Plain past negative" },
{ value: "politePastNegative", label: "Polite past negative" },
],
adverb: [{ value: "base", label: "Base form (no conjugation)" }],
};
How is the form data organized?
- Each property name matches a value from category-select.
- Each option stores an internal value and a visible label.
- The verb choices form a focused study set. They do not claim to cover every Japanese verb form.
- The Adverb list contains one base form, which prevents the interface from inventing conjugations.
- Save grammar-explorer/script.js.
- Refresh the explorer in Microsoft Edge.
You should still see the title and both controls. The Form control remains empty because the next function connects this data to the page.
Did the page stop loading correctly?
Check every comma and closing bracket inside formOptions. The Adverb array and the object both need their closing characters.
Ask for help finding a syntax problem in the form data.
Rebuild the Form dropdown
The Category control exposes its selected value through categorySelect.value. The matching array can then rebuild the Form control with native option elements.
- Add the category guidance and dropdown functions below formOptions by copying this code:
const categoryHelp = {
noun: "Japanese noun predicates use です forms.",
verb: "These are five requested study forms, not every form a Japanese verb can take.",
adjective: "Each result is identified as an い-adjective or a な-adjective.",
adverb: "Adverbs stay base-only here.",
};
function renderCards() {
cards.textContent = "";
formHelp.textContent = categoryHelp[categorySelect.value];
}
function setFormOptions(category) {
while (formSelect.options.length > 0) {
formSelect.remove(0);
}
for (const formOption of formOptions[category]) {
const option = document.createElement("option");
option.value = formOption.value;
option.text = formOption.label;
formSelect.add(option);
}
renderCards();
}
What do these functions do?
- The categoryHelp object gives each category a short accuracy note.
- The renderCards() function clears the future card area and updates that note safely.
- The setFormOptions() function removes the previous options before creating the new set.
- The calls to document.createElement("option") and formSelect.add(option) build the dropdown with native form elements.
- Find the old categorySelect.addEventListener block at the bottom of grammar-explorer/script.js.
- Replace that old listener with the final event setup below:
categorySelect.addEventListener("change", () => {
setFormOptions(categorySelect.value);
});
formSelect.addEventListener("change", renderCards);
setFormOptions(categorySelect.value);
How does the dependency stay in sync?
- The Category change listener rebuilds Form from the newly selected category.
- The Form listener prepares the page to rerender whenever its own value changes.
- The final call initializes the Noun options as soon as the page loads.
- The Form control remains after Category in reading order, so keyboard users encounter the updated control next.
- Save grammar-explorer/script.js.
Before you test the finished dependency, how many choices do you expect each category to reveal?
- Switch back to Microsoft Edge.
- Refresh the grammar explorer.
- Select Noun from the Category dropdown.
- Open the Form dropdown.
You should see four noun choices. They run from “Affirmative (non-past)” through “Past negative.”
- Select Verb from the Category dropdown.
- Open the Form dropdown.
You should see five study forms. The first is “Dictionary / plain non-past.”
- Select Adjective from the Category dropdown.
- Open the Form dropdown.
You should see eight options covering plain and polite affirmative and negative forms across non-past and past.
- Select Adverb from the Category dropdown.
- Open the Form dropdown.
You should see only “Base form (no conjugation).” The guidance below the toolbar should say that adverbs stay base-only here.
That's the mismatch fixed. Every category now exposes the grammar forms that belong to its own model.
Does Form stay empty or show the wrong list?
Check that the Category values match the keys in formOptions. Confirm that setFormOptions(categorySelect.value) appears at the bottom of the file.
Ask for help tracing the dependent dropdown update.
Use these tabs to compare all three files with the completed state for this step.
✔️ Awesome, I've got everything!
Great. Double-check that you saved all three files before moving on.
ⓧ I'd like to double check the full code
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bilingual Form Explorer</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="hero">
<p class="eyebrow">English + Japanese</p>
<h1>Bilingual Form Explorer</h1>
<p>Choose a word category, then choose the form you want to inspect.</p>
</header>
<main>
<section class="toolbar" aria-labelledby="filters-heading">
<h2 id="filters-heading">Grammar filters</h2>
<div class="controls">
<div class="field">
<label for="category-select">Category</label>
<select id="category-select">
<option value="noun" selected>Noun</option>
<option value="verb">Verb</option>
<option value="adjective">Adjective</option>
<option value="adverb">Adverb</option>
</select>
</div>
<div class="field">
<label for="form-select">Form</label>
<select id="form-select"></select>
</div>
</div>
<p id="form-help" class="form-help"></p>
</section>
<section class="results">
<div id="cards" class="cards"></div>
</section>
</main>
<script src="script.js"></script>
</body>
</html>
const categorySelect = document.getElementById("category-select");
const formSelect = document.getElementById("form-select");
const formHelp = document.getElementById("form-help");
const cards = document.getElementById("cards");
const formOptions = {
noun: [
{ value: "affirmative", label: "Affirmative (non-past)" },
{ value: "past", label: "Past affirmative" },
{ value: "negative", label: "Negative (non-past)" },
{ value: "pastNegative", label: "Past negative" },
],
verb: [
{ value: "dictionary", label: "Dictionary / plain non-past" },
{ value: "masu", label: "ます-form (polite non-past)" },
{ value: "te", label: "て-form" },
{ value: "ta", label: "た-form (plain past)" },
{ value: "nai", label: "ない-form (plain negative)" },
],
adjective: [
{ value: "plainPresent", label: "Plain non-past affirmative" },
{ value: "plainPast", label: "Plain past affirmative" },
{ value: "politePresent", label: "Polite non-past affirmative" },
{ value: "politePast", label: "Polite past affirmative" },
{ value: "plainNegative", label: "Plain non-past negative" },
{ value: "politeNegative", label: "Polite non-past negative" },
{ value: "plainPastNegative", label: "Plain past negative" },
{ value: "politePastNegative", label: "Polite past negative" },
],
adverb: [{ value: "base", label: "Base form (no conjugation)" }],
};
const categoryHelp = {
noun: "Japanese noun predicates use です forms.",
verb: "These are five requested study forms, not every form a Japanese verb can take.",
adjective: "Each result is identified as an い-adjective or a な-adjective.",
adverb: "Adverbs stay base-only here.",
};
function renderCards() {
cards.textContent = "";
formHelp.textContent = categoryHelp[categorySelect.value];
}
function setFormOptions(category) {
while (formSelect.options.length > 0) {
formSelect.remove(0);
}
for (const formOption of formOptions[category]) {
const option = document.createElement("option");
option.value = formOption.value;
option.text = formOption.label;
formSelect.add(option);
}
renderCards();
}
categorySelect.addEventListener("change", () => {
setFormOptions(categorySelect.value);
});
formSelect.addEventListener("change", renderCards);
setFormOptions(categorySelect.value);
:root {
font-family: "Segoe UI", sans-serif;
color: #172033;
background: #f4f7fb;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.hero,
main {
width: min(960px, calc(100% - 32px));
margin-inline: auto;
}
.hero {
padding: 40px 0 24px;
}
.toolbar {
position: sticky;
top: 0;
padding: 18px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: #ffffff;
}
.controls {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 14px;
}
.field {
display: grid;
gap: 6px;
}
select {
min-height: 44px;
padding: 9px 12px;
}
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
padding: 28px 0;
}
.card {
padding: 20px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: #ffffff;
}
Your controls now understand category-specific grammar. Next, you will turn each selection into bilingual Japanese and English result cards.
Render the Bilingual Grammar Cards
Your Category control now gives each word type its own Form list. The empty results area still leaves those accurate choices disconnected from the grammar examples.
A JavaScript data model gives each selection a verified Japanese form. Data-driven rendering pairs that form with a careful English comparison.
In this step, get ready to:
- Add verified noun, verb, adjective, and adverb entries.
- Build reusable functions that render cards from the selected category and form.
- Style the cards and verify the bilingual results in the browser.
Add the bilingual grammar data
Each entry stores a category, a study term, a badge, and its available forms. A separate English guide keeps comparison patterns distinct from the Japanese data.
- In grammar-explorer/index.html, replace the existing results section with the code below:
<section class="results" aria-labelledby="results-heading">
<div class="results-title">
<h2 id="results-heading">Examples</h2>
<p id="result-status"></p>
</div>
<div id="cards" class="cards"></div>
</section>
What does this markup add?
- The results-heading identifier gives the results section an accessible name.
- The result-status element provides a dedicated place for the number of displayed examples.
- The existing cards container remains the destination for the generated cards.
- Save grammar-explorer/index.html in Visual Studio Code.
- Refresh the explorer in Microsoft Edge.
You should see an Examples heading above the results area.
Examples heading missing?
Check that the replacement remains inside the existing main element. Confirm that every opening element has a matching closing element.
Ask for help checking the results markup.
✔️ Awesome, I've got everything!
Great. Your results area now has a visible heading and a place for its count.
ⓧ I'd like to double check the full code
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bilingual Form Explorer</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="hero">
<p class="eyebrow">English + Japanese</p>
<h1>Bilingual Form Explorer</h1>
<p>Choose a word category, then choose the form you want to inspect.</p>
</header>
<main>
<section class="toolbar" aria-labelledby="filters-heading">
<h2 id="filters-heading">Grammar filters</h2>
<div class="controls">
<div class="field">
<label for="category-select">Category</label>
<select id="category-select">
<option value="noun" selected>Noun</option>
<option value="verb">Verb</option>
<option value="adjective">Adjective</option>
<option value="adverb">Adverb</option>
</select>
</div>
<div class="field">
<label for="form-select">Form</label>
<select id="form-select"></select>
</div>
</div>
<p id="form-help" class="form-help"></p>
</section>
<section class="results" aria-labelledby="results-heading">
<div class="results-title">
<h2 id="results-heading">Examples</h2>
<p id="result-status"></p>
</div>
<div id="cards" class="cards"></div>
</section>
</main>
<script src="script.js"></script>
</body>
</html>
- In grammar-explorer/script.js, replace the opening data section with the code below:
const categorySelect = document.getElementById("category-select");
const formSelect = document.getElementById("form-select");
const formHelp = document.getElementById("form-help");
const cards = document.getElementById("cards");
const resultStatus = document.getElementById("result-status");
const formOptions = {
noun: [{ value: "affirmative", label: "Affirmative (non-past)" }, { value: "past", label: "Past affirmative" }, { value: "negative", label: "Negative (non-past)" }, { value: "pastNegative", label: "Past negative" }],
verb: [{ value: "dictionary", label: "Dictionary / plain non-past" }, { value: "masu", label: "ます-form (polite non-past)" }, { value: "te", label: "て-form" }, { value: "ta", label: "た-form (plain past)" }, { value: "nai", label: "ない-form (plain negative)" }],
adjective: [{ value: "plainPresent", label: "Plain non-past affirmative" }, { value: "plainPast", label: "Plain past affirmative" }, { value: "politePresent", label: "Polite non-past affirmative" }, { value: "politePast", label: "Polite past affirmative" }, { value: "plainNegative", label: "Plain non-past negative" }, { value: "politeNegative", label: "Polite non-past negative" }, { value: "plainPastNegative", label: "Plain past negative" }, { value: "politePastNegative", label: "Polite past negative" }],
adverb: [{ value: "base", label: "Base form (no conjugation)" }],
};
const categoryHelp = { noun: "Japanese noun predicates use です forms. English comparison patterns use the verb be.", verb: "These are five requested study forms, not every form a Japanese verb can take.", adjective: "Each result is identified as an い-adjective or a な-adjective.", adverb: "Adverbs stay base-only here. Tense belongs to the sentence's verb." };
const englishGuides = { noun: { affirmative: "am/is/are + noun", past: "was/were + noun", negative: "am/is/are not + noun", pastNegative: "was/were not + noun" }, verb: { dictionary: "base verb", masu: "present meaning in a polite Japanese form", te: "no single English tense label", ta: "past simple verb", nai: "do/does not + base verb" }, adjective: { plainPresent: "am/is/are + adjective", plainPast: "was/were + adjective", politePresent: "am/is/are + adjective", politePast: "was/were + adjective", plainNegative: "am/is/are not + adjective", politeNegative: "am/is/are not + adjective", plainPastNegative: "was/were not + adjective", politePastNegative: "was/were not + adjective" }, adverb: { base: "The adverb stays unchanged; the sentence's verb carries tense." } };
const entries = [
{ category: "noun", term: "N", badge: "Noun predicate", forms: { affirmative: "Nです", past: "Nでした", negative: "Nではありません", pastNegative: "Nではありませんでした" } },
{ category: "verb", group: "group1", term: "かく", badge: "Group 1 verb", forms: { dictionary: "かく", masu: "かきます", te: "かいて", ta: "かいた", nai: "かかない" } },
{ category: "verb", group: "group2", term: "たべる", badge: "Group 2 verb", forms: { dictionary: "たべる", masu: "たべます", te: "たべて", ta: "たべた", nai: "たべない" } },
{ category: "verb", group: "group3", term: "する", badge: "Group 3 verb", forms: { dictionary: "する", masu: "します", te: "して", ta: "した", nai: "しない" } },
{ category: "adjective", term: "あつい", badge: "い-adjective", forms: { plainPresent: "あつい", plainPast: "あつかった", politePresent: "あついです", politePast: "あつかったです", plainNegative: "あつくない", politeNegative: "あつくないです", plainPastNegative: "あつくなかった", politePastNegative: "あつくなかったです" } },
{ category: "adjective", term: "すき", badge: "な-adjective", forms: { plainPresent: "すきだ", plainPast: "すきだった", politePresent: "すきです", politePast: "すきでした", plainNegative: "すきではない", politeNegative: "すきではありません", plainPastNegative: "すきではなかった", politePastNegative: "すきではありませんでした" } },
{ category: "adverb", term: "副詞", badge: "Adverb", forms: { base: "副詞" } },
];
How is the grammar data organized?
- The englishGuides object maps each selected form to an English comparison pattern.
- The entries array stores one noun pattern, three verb groups, two adjective types, and one base-only adverb.
- Each forms object uses the same keys as its category inside formOptions.
- Save grammar-explorer/script.js.
- Refresh the explorer in Microsoft Edge.
The Noun helper now includes the English comparison sentence. The Examples heading remains visible.
Helper text disappeared?
Check that the replacement ends after the closing bracket of entries. Confirm that the existing functions remain below it.
Ask for help checking the data section.
Build the card renderer
The renderer creates each card with document.createElement(). It uses textContent for text before attaching each element with appendChild().
- In grammar-explorer/script.js, insert this helper immediately above renderCards:
function createTextRow(label, text) {
const row = document.createElement("p");
const labelNode = document.createElement("strong");
const valueNode = document.createElement("span");
labelNode.textContent = label;
valueNode.textContent = text;
row.appendChild(labelNode);
row.appendChild(valueNode);
return row;
}
What does this helper do?
- The helper creates one paragraph containing a strong label and a text value.
- Returning the completed row lets renderCards reuse the same structure for Japanese forms and English guides.
- Save grammar-explorer/script.js.
- Refresh the explorer in Microsoft Edge.
The page should still display the Noun helper text beneath the dropdowns. This confirms the new helper does not stop the script from loading.
Helper text is blank?
Check the braces around createTextRow. Make sure the function sits above the existing renderCards function.
Ask for help finding the syntax issue.
- Replace the existing renderCards function with the code below:
function renderCards() {
const category = categorySelect.value;
const form = formSelect.value;
let count = 0;
cards.textContent = "";
formHelp.textContent = categoryHelp[category];
for (const entry of entries) {
if (entry.category !== category) continue;
const article = document.createElement("article");
const heading = document.createElement("h3");
const badge = document.createElement("span");
article.className = "card";
heading.textContent = entry.term;
badge.className = "badge";
badge.textContent = entry.badge;
article.appendChild(heading);
article.appendChild(badge);
article.appendChild(createTextRow("Japanese form", entry.forms[form]));
article.appendChild(createTextRow("English guide", englishGuides[category][form]));
cards.appendChild(article);
count += 1;
}
resultStatus.textContent = `${count} example${count === 1 ? "" : "s"} shown.`;
}
How does rendering work?
- The selected category and form determine which entries and values appear.
- The category check skips entries that do not match the current selection.
- Each matching entry becomes an article with a heading, a badge, a Japanese row, and an English row.
- The final status reports how many cards were appended.
- Save grammar-explorer/script.js.
- Refresh the explorer in Microsoft Edge.
You should see one Noun predicate card showing Nです with the English guide am/is/are + noun. The result count should read 1 example shown..
Card missing or undefined?
Check that every form key in entries matches a value in formOptions. Confirm that resultStatus points to the new result-status element.
Ask for help tracing the selected form.
✔️ Awesome, I've got everything!
Excellent. Your selections now produce bilingual grammar cards from the data model.
ⓧ I'd like to double check the full code
const categorySelect = document.getElementById("category-select");
const formSelect = document.getElementById("form-select");
const formHelp = document.getElementById("form-help");
const cards = document.getElementById("cards");
const resultStatus = document.getElementById("result-status");
const formOptions = {
noun: [{ value: "affirmative", label: "Affirmative (non-past)" }, { value: "past", label: "Past affirmative" }, { value: "negative", label: "Negative (non-past)" }, { value: "pastNegative", label: "Past negative" }],
verb: [{ value: "dictionary", label: "Dictionary / plain non-past" }, { value: "masu", label: "ます-form (polite non-past)" }, { value: "te", label: "て-form" }, { value: "ta", label: "た-form (plain past)" }, { value: "nai", label: "ない-form (plain negative)" }],
adjective: [{ value: "plainPresent", label: "Plain non-past affirmative" }, { value: "plainPast", label: "Plain past affirmative" }, { value: "politePresent", label: "Polite non-past affirmative" }, { value: "politePast", label: "Polite past affirmative" }, { value: "plainNegative", label: "Plain non-past negative" }, { value: "politeNegative", label: "Polite non-past negative" }, { value: "plainPastNegative", label: "Plain past negative" }, { value: "politePastNegative", label: "Polite past negative" }],
adverb: [{ value: "base", label: "Base form (no conjugation)" }],
};
const categoryHelp = { noun: "Japanese noun predicates use です forms. English comparison patterns use the verb be.", verb: "These are five requested study forms, not every form a Japanese verb can take.", adjective: "Each result is identified as an い-adjective or a な-adjective.", adverb: "Adverbs stay base-only here. Tense belongs to the sentence's verb." };
const englishGuides = { noun: { affirmative: "am/is/are + noun", past: "was/were + noun", negative: "am/is/are not + noun", pastNegative: "was/were not + noun" }, verb: { dictionary: "base verb", masu: "present meaning in a polite Japanese form", te: "no single English tense label", ta: "past simple verb", nai: "do/does not + base verb" }, adjective: { plainPresent: "am/is/are + adjective", plainPast: "was/were + adjective", politePresent: "am/is/are + adjective", politePast: "was/were + adjective", plainNegative: "am/is/are not + adjective", politeNegative: "am/is/are not + adjective", plainPastNegative: "was/were not + adjective", politePastNegative: "was/were not + adjective" }, adverb: { base: "The adverb stays unchanged; the sentence's verb carries tense." } };
const entries = [
{ category: "noun", term: "N", badge: "Noun predicate", forms: { affirmative: "Nです", past: "Nでした", negative: "Nではありません", pastNegative: "Nではありませんでした" } },
{ category: "verb", group: "group1", term: "かく", badge: "Group 1 verb", forms: { dictionary: "かく", masu: "かきます", te: "かいて", ta: "かいた", nai: "かかない" } },
{ category: "verb", group: "group2", term: "たべる", badge: "Group 2 verb", forms: { dictionary: "たべる", masu: "たべます", te: "たべて", ta: "たべた", nai: "たべない" } },
{ category: "verb", group: "group3", term: "する", badge: "Group 3 verb", forms: { dictionary: "する", masu: "します", te: "して", ta: "した", nai: "しない" } },
{ category: "adjective", term: "あつい", badge: "い-adjective", forms: { plainPresent: "あつい", plainPast: "あつかった", politePresent: "あついです", politePast: "あつかったです", plainNegative: "あつくない", politeNegative: "あつくないです", plainPastNegative: "あつくなかった", politePastNegative: "あつくなかったです" } },
{ category: "adjective", term: "すき", badge: "な-adjective", forms: { plainPresent: "すきだ", plainPast: "すきだった", politePresent: "すきです", politePast: "すきでした", plainNegative: "すきではない", politeNegative: "すきではありません", plainPastNegative: "すきではなかった", politePastNegative: "すきではありませんでした" } },
{ category: "adverb", term: "副詞", badge: "Adverb", forms: { base: "副詞" } },
];
function createTextRow(label, text) {
const row = document.createElement("p");
const labelNode = document.createElement("strong");
const valueNode = document.createElement("span");
labelNode.textContent = label;
valueNode.textContent = text;
row.appendChild(labelNode);
row.appendChild(valueNode);
return row;
}
function renderCards() {
const category = categorySelect.value;
const form = formSelect.value;
let count = 0;
cards.textContent = "";
formHelp.textContent = categoryHelp[category];
for (const entry of entries) {
if (entry.category !== category) continue;
const article = document.createElement("article");
const heading = document.createElement("h3");
const badge = document.createElement("span");
article.className = "card";
heading.textContent = entry.term;
badge.className = "badge";
badge.textContent = entry.badge;
article.appendChild(heading);
article.appendChild(badge);
article.appendChild(createTextRow("Japanese form", entry.forms[form]));
article.appendChild(createTextRow("English guide", englishGuides[category][form]));
cards.appendChild(article);
count += 1;
}
resultStatus.textContent = `${count} example${count === 1 ? "" : "s"} shown.`;
}
function setFormOptions(category) {
while (formSelect.options.length > 0) formSelect.remove(0);
for (const formOption of formOptions[category]) {
const option = document.createElement("option");
option.value = formOption.value;
option.text = formOption.label;
formSelect.add(option);
}
renderCards();
}
categorySelect.addEventListener("change", () => setFormOptions(categorySelect.value));
formSelect.addEventListener("change", renderCards);
setFormOptions(categorySelect.value);
Style and verify the cards
The card data is working. A shared grid rule now keeps the controls and generated cards visually consistent.
- In grammar-explorer/styles.css, replace the existing .controls rule with the code below:
.controls,
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 14px;
}
Why share the grid rule?
Both the toolbar controls and the result cards use flexible columns. One shared rule keeps their minimum width and spacing aligned.
- Delete the older .cards rule that uses minmax(240px, 1fr).
- Save grammar-explorer/styles.css.
- Refresh the explorer in Microsoft Edge.
The result cards should remain arranged in a grid with the same gap used by the controls.
Cards lost their grid?
Check that the selector begins with .controls, and continues with .cards before the opening brace.
Ask for help checking the shared selector.
- Replace the section from the existing select rule through the end of grammar-explorer/styles.css with the code below:
select {
min-height: 44px;
padding: 9px 12px;
}
.results {
padding: 28px 0;
}
.card {
padding: 20px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: #ffffff;
}
.badge {
color: #4d2d99;
font-weight: 700;
}
What does this styling change?
- The .results rule creates space around the generated card grid.
- The .card rule gives each example a bordered white surface.
- The .badge rule distinguishes the grammar type with purple bold text.
- Save grammar-explorer/styles.css.
- Refresh the explorer in Microsoft Edge.
The card should have a white background, a rounded border, and a purple grammar badge.
Badge styling missing?
Check that the stylesheet still loads from styles.css. Confirm that the CSS selector is .badge and the rendered span uses the same class.
Ask for help tracing the missing style.
✔️ Awesome, I've got everything!
Your generated cards now have the complete styling for this step.
ⓧ I'd like to double check the full code
:root {
font-family: "Segoe UI", sans-serif;
color: #172033;
background: #f4f7fb;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
.hero,
main {
width: min(960px, calc(100% - 32px));
margin-inline: auto;
}
.hero {
padding: 40px 0 24px;
}
.toolbar {
position: sticky;
top: 0;
padding: 18px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: #ffffff;
}
.controls,
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 14px;
}
.field {
display: grid;
gap: 6px;
}
select {
min-height: 44px;
padding: 9px 12px;
}
.results {
padding: 28px 0;
}
.card {
padding: 20px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: #ffffff;
}
.badge {
color: #4d2d99;
font-weight: 700;
}
Before you change the final selections, which three Japanese forms do you expect the Verb cards to show for て-form?
- Return to the explorer in Microsoft Edge.
- Select Verb from the Category dropdown.
- Select て-form from the Form dropdown.
You should see three cards showing かいて, たべて, and して. The status should read 3 examples shown..
- Select Adjective from the Category dropdown.
- Select Plain non-past affirmative from the Form dropdown.
You should see あつい badged as い-adjective. You should also see すき badged as な-adjective.
- Select Noun from the Category dropdown.
You should see one generic predicate card showing Nです.
- Select Adverb from the Category dropdown.
You should see one 副詞 card with the base-only guidance. That is the grammar model working across all four categories.
Your explorer now turns every category and form selection into a bilingual grammar reference. Next up, you will make those dynamic results responsive, keyboard-usable, and politely announced.
Make the Explorer Responsive and Accessible
Your explorer now turns each category selection into bilingual grammar cards. The original three-mode quiz also remains intact in the parent folder.
Dynamic results need to stay readable on narrow screens. An accessible live region also needs to announce each update without moving keyboard focus.
In this step, get ready to:
- Finish the responsive layout with flexible controls and cards.
- Add visible focus styles and polite result announcements.
- Test every category with the keyboard in Microsoft Edge.
Finish the responsive layout
Responsive CSS lets the controls and cards adapt to the available width. The first update also gives the page a consistent height and styles the small heading above the title.
- Switch back to styles.css in Visual Studio Code.
- Apply the page foundation updates by replacing the matching blocks with this code:
:root {
color-scheme: light;
font-family: "Segoe UI", sans-serif;
color: #172033;
background: #f4f7fb;
}
body {
margin: 0;
min-height: 100vh;
}
.eyebrow {
margin: 0 0 6px;
color: #526173;
font-size: 0.82rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
}
What does this CSS do?
- The root styles establish the page colours and declare a light colour scheme.
- The body fills at least the height of the browser window.
- The eyebrow styles separate the bilingual label from the main title.
- Save styles.css.
- Return to Microsoft Edge and refresh the explorer.
You should see a spaced uppercase label above the explorer title. The page background should fill the browser window.
Does the eyebrow still look plain?
Check that the selector begins with a dot and matches class="eyebrow" in index.html.
Ask for help if the selector still does not apply: Why is my .eyebrow CSS not applying to the paragraph?
The toolbar stays visible while the learner moves through the results. Clear spacing and contrast make that fixed position easier to follow.
- Update the heading and toolbar selectors by replacing the matching blocks with this code:
h1,
h2,
p {
margin-top: 0;
}
h1 {
margin-bottom: 10px;
font-size: clamp(2rem, 6vw, 3.4rem);
}
.toolbar {
position: sticky;
top: 0;
z-index: 10;
padding: 18px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: rgba(255, 255, 255, 0.96);
box-shadow: 0 12px 30px rgba(32, 48, 77, 0.1);
}
.toolbar h2 {
margin-bottom: 14px;
font-size: 1rem;
}
How does the toolbar stay readable?
- The title size scales with the browser width while staying within a readable range.
- The toolbar uses a high stacking position so cards move behind it.
- The nearly opaque background and shadow separate the sticky toolbar from those cards.
- Save styles.css.
- Refresh the explorer in Microsoft Edge.
- Scroll down through the result cards.
You should see the toolbar remain at the top of the page. The cards should pass behind its white background and shadow.
Does the toolbar scroll away?
Confirm that position: sticky and top: 0 remain inside the .toolbar block.
Ask for help if the toolbar still moves away: Why is my sticky grammar toolbar not staying at the top?
Each native dropdown needs a clear label and a large target. A visible focus outline also shows which control receives keyboard input.
- Update the control selectors by replacing the matching blocks with this code:
.controls {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 14px;
}
label {
font-size: 0.9rem;
font-weight: 700;
}
select {
width: 100%;
min-height: 44px;
padding: 9px 12px;
border: 1px solid #91a0b5;
border-radius: 10px;
color: #172033;
background: #ffffff;
font: inherit;
}
select:focus-visible {
outline: 3px solid #7957d5;
outline-offset: 2px;
}
What makes the controls keyboard-friendly?
- The control grid creates as many columns as the available width can hold.
- Each dropdown fills its grid column and keeps a minimum height of 44px.
- The :focus-visible selector draws a purple outline around the active dropdown.
- Save styles.css.
- Refresh the explorer in Microsoft Edge.
- Press Tab until the Category dropdown receives focus.
You should see a purple outline around the Category dropdown. Its visible Category label should remain directly above it.
Is the focus outline missing?
Use the keyboard to focus the dropdown because :focus-visible may stay hidden after a mouse click.
Ask for help if keyboard focus remains invisible: Why is my select focus-visible outline missing?
The result heading and card grid need room to rearrange independently. This layout keeps the count readable while letting cards wrap into new rows.
- Update the result layout by replacing the matching blocks with this code:
.form-help {
margin: 12px 0 0;
color: #526173;
}
.results {
padding: 28px 0 48px;
}
.results-title {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 16px;
}
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}
How does the result area adapt?
- The helper text receives its own spacing and muted colour.
- The result heading and status share a flexible row.
- The card grid wraps whenever another 240px column cannot fit.
- Save styles.css.
- Refresh the explorer in Microsoft Edge.
- Resize the browser window to compare wide and narrow layouts.
You should see the cards move between multiple columns and a single column as the available width changes.
Do the cards stay in one narrow column?
Confirm that the .cards selector contains the responsive repeat(auto-fit, minmax(240px, 1fr)) value.
Ask for help if the grid does not wrap: Why is my responsive card grid not creating extra columns?
Each card needs a clear top row for its Japanese term and grammar badge. The spacing below that row separates identity from the bilingual form details.
- Update the card structure styles by replacing the matching block and adding the new selectors below it:
.card {
padding: 20px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: #ffffff;
box-shadow: 0 8px 20px rgba(32, 48, 77, 0.07);
}
.card-top {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 18px;
}
.card h3 {
margin: 0;
font-size: 1.65rem;
}
What changes inside each card?
- The card shadow separates each example from the page background.
- The top row keeps the term and badge aligned on opposite sides.
- The larger heading makes the source term easier to scan.
- Save styles.css.
- Refresh the explorer in Microsoft Edge.
The card shadow should now be visible. The term and badge alignment appears after the JavaScript structure is updated in the next substep.
Is the card shadow missing?
Check that the new box-shadow declaration sits inside the existing .card selector.
Ask for help if the card remains flat: Why is my .card box shadow not visible?
Labels and values become easier to distinguish when they have separate visual roles. Larger Japanese text also makes small character differences easier to inspect.
- Finish the card typography by replacing the badge block and adding the text-row selectors below it:
.badge {
padding: 5px 9px;
border-radius: 999px;
color: #4d2d99;
background: #eee8ff;
font-size: 0.78rem;
font-weight: 700;
}
.text-row {
display: grid;
gap: 4px;
margin-bottom: 14px;
}
.text-row strong {
color: #526173;
font-size: 0.78rem;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.japanese-value {
font-size: 1.35rem;
}
Why separate labels from values?
- The badge uses a compact pill shape to identify the grammar type.
- Each text row stacks its label above its value.
- The Japanese form receives a larger size than the English guide.
- Save styles.css.
- Refresh the explorer in Microsoft Edge.
You should see rounded purple badges. The new row and Japanese text styles appear fully after the rendering update in the next substep.
Does the badge still look like plain text?
Confirm that the JavaScript still assigns badge as the element class.
Ask for help if the badge styles remain absent: Why is my .badge CSS not styling the generated span?
A narrow-screen rule reduces the outer spacing and lets the result heading stack above its status. The desktop layout remains unchanged above the breakpoint.
- Add the narrow-screen rule at the end of styles.css by pasting this code:
@media (max-width: 600px) {
.hero,
main {
width: min(100% - 20px, 960px);
}
.hero {
padding-top: 24px;
}
.toolbar {
border-radius: 12px;
}
.results-title {
display: block;
}
}
What changes on narrow screens?
- The page uses smaller side margins below 600px.
- The hero and toolbar use tighter spacing.
- The result status moves below the Examples heading.
- Save styles.css.
- Refresh the explorer in Microsoft Edge.
- Narrow the browser window until the controls and cards stack.
You should see one control per row and one card per row. The result status should sit below the Examples heading.
Does the narrow layout stay unchanged?
Check that the media rule closes with its final brace and remains at the end of styles.css.
Ask for help if the breakpoint does not apply: Why is my max-width media query not changing the grammar explorer layout?
✔️ Awesome, I've got everything!
Great. Save styles.css before moving to the accessible result updates.
ⓧ I'd like to double check the full code
:root {
color-scheme: light;
font-family: "Segoe UI", sans-serif;
color: #172033;
background: #f4f7fb;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
}
.hero,
main {
width: min(960px, calc(100% - 32px));
margin-inline: auto;
}
.hero {
padding: 40px 0 24px;
}
.eyebrow {
margin: 0 0 6px;
color: #526173;
font-size: 0.82rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
}
h1,
h2,
p {
margin-top: 0;
}
h1 {
margin-bottom: 10px;
font-size: clamp(2rem, 6vw, 3.4rem);
}
.toolbar {
position: sticky;
top: 0;
z-index: 10;
padding: 18px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: rgba(255, 255, 255, 0.96);
box-shadow: 0 12px 30px rgba(32, 48, 77, 0.1);
}
.toolbar h2 {
margin-bottom: 14px;
font-size: 1rem;
}
.controls {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 14px;
}
.field {
display: grid;
gap: 6px;
}
label {
font-size: 0.9rem;
font-weight: 700;
}
select {
width: 100%;
min-height: 44px;
padding: 9px 12px;
border: 1px solid #91a0b5;
border-radius: 10px;
color: #172033;
background: #ffffff;
font: inherit;
}
select:focus-visible {
outline: 3px solid #7957d5;
outline-offset: 2px;
}
.form-help {
margin: 12px 0 0;
color: #526173;
}
.results {
padding: 28px 0 48px;
}
.results-title {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 16px;
}
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}
.card {
padding: 20px;
border: 1px solid #d8dfeb;
border-radius: 16px;
background: #ffffff;
box-shadow: 0 8px 20px rgba(32, 48, 77, 0.07);
}
.card-top {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 18px;
}
.card h3 {
margin: 0;
font-size: 1.65rem;
}
.badge {
padding: 5px 9px;
border-radius: 999px;
color: #4d2d99;
background: #eee8ff;
font-size: 0.78rem;
font-weight: 700;
}
.text-row {
display: grid;
gap: 4px;
margin-bottom: 14px;
}
.text-row strong {
color: #526173;
font-size: 0.78rem;
letter-spacing: 0.04em;
text-transform: uppercase;
}
.japanese-value {
font-size: 1.35rem;
}
@media (max-width: 600px) {
.hero,
main {
width: min(100% - 20px, 960px);
}
.hero {
padding-top: 24px;
}
.toolbar {
border-radius: 12px;
}
.results-title {
display: block;
}
}
How to use this reference
Compare this file with your saved styles.css. Check selector order and closing braces before continuing.
Add accessible result updates
The existing labels already connect Category and Form to their matching dropdowns. The result status now needs to announce its changing text through a polite live region.
- Switch back to index.html in Visual Studio Code.
- Replace the existing results section with this updated section:
<section class="results" aria-labelledby="results-heading">
<div class="results-title">
<h2 id="results-heading">Examples</h2>
<p id="result-status" aria-live="polite"></p>
</div>
<div id="cards" class="cards"></div>
</section>
What does the live region do?
The aria-live="polite" attribute lets assistive technology announce status updates when the current task permits. Keyboard focus stays on the dropdown that caused the update.
- Save index.html.
- Refresh the explorer in Microsoft Edge.
You should still see the Examples heading and the current result count. The attribute adds announcement behavior without adding visible text.
Did the result status disappear?
Confirm that the paragraph still uses id="result-status". The JavaScript uses that exact ID to update its text.
Ask for help if the count remains missing: Why is my result-status paragraph no longer updating?
✔️ Awesome, I've got everything!
Your result status now has the polite live-region attribute. Keep index.html saved.
ⓧ I'd like to double check the full code
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bilingual Form Explorer</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="hero">
<p class="eyebrow">English + Japanese</p>
<h1>Bilingual Form Explorer</h1>
<p>Choose a word category, then choose the form you want to inspect.</p>
</header>
<main>
<section class="toolbar" aria-labelledby="filters-heading">
<h2 id="filters-heading">Grammar filters</h2>
<div class="controls">
<div class="field">
<label for="category-select">Category</label>
<select id="category-select">
<option value="noun" selected>Noun</option>
<option value="verb">Verb</option>
<option value="adjective">Adjective</option>
<option value="adverb">Adverb</option>
</select>
</div>
<div class="field">
<label for="form-select">Form</label>
<select id="form-select"></select>
</div>
</div>
<p id="form-help" class="form-help"></p>
</section>
<section class="results" aria-labelledby="results-heading">
<div class="results-title">
<h2 id="results-heading">Examples</h2>
<p id="result-status" aria-live="polite"></p>
</div>
<div id="cards" class="cards"></div>
</section>
</main>
<script src="script.js"></script>
</body>
</html>
How to use this reference
Compare the results section carefully. The live-region attribute belongs on the paragraph with id="result-status".
The new CSS classes need matching elements in the generated cards. The helper can assign a class to selected values while keeping the English guide at its normal size.
- Switch back to script.js in Visual Studio Code.
- Replace the existing createTextRow function with this version:
function createTextRow(label, text, valueClass = "") { const row = document.createElement("p"); const labelNode = document.createElement("strong"); const valueNode = document.createElement("span"); row.className = "text-row"; labelNode.textContent = label; valueNode.textContent = text; valueNode.className = valueClass; row.appendChild(labelNode); row.appendChild(valueNode); return row; }
What does the updated helper do?
- The optional valueClass parameter identifies values that need extra styling.
- The paragraph receives the text-row class used by the grid layout.
- The value span receives the supplied class before the row is returned.
- Save script.js.
- Refresh the explorer in Microsoft Edge.
You should see each Japanese form label stacked above its value. The English guide should use the same row spacing.
Are the labels still inline?
Check that row.className = "text-row" appears before the helper returns the row.
Ask for help if the layout remains unchanged: Why is createTextRow not applying the text-row class?
The renderer can now group each term with its badge and mark the Japanese form for larger text. It continues to update the result status through textContent after every selection.
- Replace the existing renderCards function with this version:
function renderCards() { const category = categorySelect.value; const form = formSelect.value; let count = 0; cards.textContent = ""; formHelp.textContent = categoryHelp[category]; for (const entry of entries) { if (entry.category !== category) continue; const article = document.createElement("article"); const top = document.createElement("div"); const heading = document.createElement("h3"); const badge = document.createElement("span"); article.className = "card"; top.className = "card-top"; heading.textContent = entry.term; badge.className = "badge"; badge.textContent = entry.badge; top.appendChild(heading); top.appendChild(badge); article.appendChild(top); article.appendChild(createTextRow("Japanese form", entry.forms[form], "japanese-value")); article.appendChild(createTextRow("English guide", englishGuides[category][form])); cards.appendChild(article); count += 1; } resultStatus.textContent = `${count} example${count === 1 ? "" : "s"} shown.`; }
How does the final renderer work?
- The card-top container groups the term with its badge.
- The Japanese form receives the japanese-value class for larger text.
- The final status assignment reports the rendered count through the polite live region.
- Save script.js.
- Refresh the explorer in Microsoft Edge.
- Select Verb from the Category dropdown.
You should see three cards with each term and group badge aligned across the top. The Japanese forms should be larger than their English guides.
Are the card tops misaligned?
Confirm that the heading and badge are appended to top. The top element must be appended to article before the text rows.
Ask for help if the generated structure is wrong: Why is my renderCards card-top layout not working?
✔️ Awesome, I've got everything!
Your renderer now supplies every class required by the finished card design. Save script.js.
ⓧ I'd like to double check the full code
const categorySelect = document.getElementById("category-select");
const formSelect = document.getElementById("form-select");
const formHelp = document.getElementById("form-help");
const cards = document.getElementById("cards");
const resultStatus = document.getElementById("result-status");
const formOptions = {
noun: [{ value: "affirmative", label: "Affirmative (non-past)" }, { value: "past", label: "Past affirmative" }, { value: "negative", label: "Negative (non-past)" }, { value: "pastNegative", label: "Past negative" }],
verb: [{ value: "dictionary", label: "Dictionary / plain non-past" }, { value: "masu", label: "ます-form (polite non-past)" }, { value: "te", label: "て-form" }, { value: "ta", label: "た-form (plain past)" }, { value: "nai", label: "ない-form (plain negative)" }],
adjective: [{ value: "plainPresent", label: "Plain non-past affirmative" }, { value: "plainPast", label: "Plain past affirmative" }, { value: "politePresent", label: "Polite non-past affirmative" }, { value: "politePast", label: "Polite past affirmative" }, { value: "plainNegative", label: "Plain non-past negative" }, { value: "politeNegative", label: "Polite non-past negative" }, { value: "plainPastNegative", label: "Plain past negative" }, { value: "politePastNegative", label: "Polite past negative" }],
adverb: [{ value: "base", label: "Base form (no conjugation)" }],
};
const categoryHelp = { noun: "Japanese noun predicates use です forms. English comparison patterns use the verb be.", verb: "These are five requested study forms, not every form a Japanese verb can take.", adjective: "Each result is identified as an い-adjective or a な-adjective.", adverb: "Adverbs stay base-only here. Tense belongs to the sentence's verb." };
const englishGuides = { noun: { affirmative: "am/is/are + noun", past: "was/were + noun", negative: "am/is/are not + noun", pastNegative: "was/were not + noun" }, verb: { dictionary: "base verb", masu: "present meaning in a polite Japanese form", te: "no single English tense label", ta: "past simple verb", nai: "do/does not + base verb" }, adjective: { plainPresent: "am/is/are + adjective", plainPast: "was/were + adjective", politePresent: "am/is/are + adjective", politePast: "was/were + adjective", plainNegative: "am/is/are not + adjective", politeNegative: "am/is/are not + adjective", plainPastNegative: "was/were not + adjective", politePastNegative: "was/were not + adjective" }, adverb: { base: "The adverb stays unchanged; the sentence's verb carries tense." } };
const entries = [{ category: "noun", term: "N", badge: "Noun predicate", forms: { affirmative: "Nです", past: "Nでした", negative: "Nではありません", pastNegative: "Nではありませんでした" } }, { category: "verb", group: "group1", term: "かく", badge: "Group 1 verb", forms: { dictionary: "かく", masu: "かきます", te: "かいて", ta: "かいた", nai: "かかない" } }, { category: "verb", group: "group2", term: "たべる", badge: "Group 2 verb", forms: { dictionary: "たべる", masu: "たべます", te: "たべて", ta: "たべた", nai: "たべない" } }, { category: "verb", group: "group3", term: "する", badge: "Group 3 verb", forms: { dictionary: "する", masu: "します", te: "して", ta: "した", nai: "しない" } }, { category: "adjective", term: "あつい", badge: "い-adjective", forms: { plainPresent: "あつい", plainPast: "あつかった", politePresent: "あついです", politePast: "あつかったです", plainNegative: "あつくない", politeNegative: "あつくないです", plainPastNegative: "あつくなかった", politePastNegative: "あつくなかったです" } }, { category: "adjective", term: "すき", badge: "な-adjective", forms: { plainPresent: "すきだ", plainPast: "すきだった", politePresent: "すきです", politePast: "すきでした", plainNegative: "すきではない", politeNegative: "すきではありません", plainPastNegative: "すきではなかった", politePastNegative: "すきではありませんでした" } }, { category: "adverb", term: "副詞", badge: "Adverb", forms: { base: "副詞" } }];
function createTextRow(label, text, valueClass = "") { const row = document.createElement("p"); const labelNode = document.createElement("strong"); const valueNode = document.createElement("span"); row.className = "text-row"; labelNode.textContent = label; valueNode.textContent = text; valueNode.className = valueClass; row.appendChild(labelNode); row.appendChild(valueNode); return row; }
function renderCards() { const category = categorySelect.value; const form = formSelect.value; let count = 0; cards.textContent = ""; formHelp.textContent = categoryHelp[category]; for (const entry of entries) { if (entry.category !== category) continue; const article = document.createElement("article"); const top = document.createElement("div"); const heading = document.createElement("h3"); const badge = document.createElement("span"); article.className = "card"; top.className = "card-top"; heading.textContent = entry.term; badge.className = "badge"; badge.textContent = entry.badge; top.appendChild(heading); top.appendChild(badge); article.appendChild(top); article.appendChild(createTextRow("Japanese form", entry.forms[form], "japanese-value")); article.appendChild(createTextRow("English guide", englishGuides[category][form])); cards.appendChild(article); count += 1; } resultStatus.textContent = `${count} example${count === 1 ? "" : "s"} shown.`; }
function setFormOptions(category) { while (formSelect.options.length > 0) formSelect.remove(0); for (const formOption of formOptions[category]) { const option = document.createElement("option"); option.value = formOption.value; option.text = formOption.label; formSelect.add(option); } renderCards(); }
categorySelect.addEventListener("change", () => setFormOptions(categorySelect.value));
formSelect.addEventListener("change", renderCards);
setFormOptions(categorySelect.value);
How to use this reference
Compare the two rendering functions with your saved file. Confirm that the existing data and event listeners remain present.
Test every path with the keyboard
Native dropdowns already support keyboard interaction in the browser. This final test checks focus visibility, category-specific forms, live result updates, and the untouched original quiz.
- Return to the explorer in Microsoft Edge.
- Press Tab until the Category dropdown receives the purple focus outline.
- Use the arrow keys to select Verb.
- Press Tab to move focus to the Form dropdown.
- Use the arrow keys to select て-form.
You should see かいて, たべて, and して. The status should report three examples without taking focus away from Form.
What has this proved?
The Category and Form controls both work without a mouse. The visible outline tracks focus while the cards and status update independently.
- Press Shift+Tab to return to Category.
- Use the arrow keys to select Adjective.
- Press Tab to return to Form.
- Use the arrow keys to inspect all eight adjective options.
Each option should show two cards. The badges should identify あつい as an い-adjective and すき as a な-adjective.
Before the final category check, what do you expect the Form control to contain.
- Press Shift+Tab to return to Category.
- Use the arrow keys to select Adverb.
- Press Tab to move focus to Form.
You should see only Base form (no conjugation) in Form. The status should report one example while focus remains visible.
- Return to the original quiz page from earlier.
- Check each of its three modes.
The original quiz should still work exactly as it did before this extension. Your new explorer remains isolated inside grammar-explorer.
Does keyboard selection fail to update the cards?
Check that both dropdowns still register their change listeners. Also confirm that the Category dropdown appears before Form in the HTML reading order.
Ask for help if the cards or status remain stale: Why are my keyboard dropdown changes not updating renderCards?
That completes the explorer. It now adapts to narrow screens, preserves visible keyboard focus, and announces every result update without moving the learner away from the controls.
Secret mission
Filter Verbs by Group
Your verb entries already carry Group 1, Group 2, or Group 3 identifiers. Add a third dropdown that uses those identifiers to show one verb group at a time.
Clean Up Your Resources
Clean Up Your Resources
Choose whether to keep the explorer available, close your tools for now, or delete the explorer entirely. All project files stay on your Windows device, so there are no ongoing costs.
Resources you used:
- The local grammar-explorer subfolder that contains your bilingual form explorer.
Keep everything running
Keeping the subfolder preserves the complete explorer for future Japanese study. No background service runs when the page is closed.
- Keep grammar-explorer/index.html for the page structure.
- Keep grammar-explorer/styles.css for the responsive layout.
- Keep grammar-explorer/script.js for the dependent dropdowns.
- Leave the original quiz files untouched.
Pause - I'll come back to this later
This static explorer has no server or hosted resource to pause. Closing your development tools frees local memory while every project file stays available.
- Close the explorer tab in Microsoft Edge.
- Close Visual Studio Code.
- Keep the grammar-explorer subfolder inside the existing quiz folder.
Delete - I don't want to use this again
Deleting removes only the explorer subfolder. The original three-mode quiz stays in place.
- Switch back to Visual Studio Code.
- Locate the grammar-explorer subfolder in the file tree for the existing quiz folder.
- Right-click the grammar-explorer subfolder.
- Select the option that removes the folder from disk.
- Approve the deletion confirmation.
- Confirm that grammar-explorer is no longer listed.
- Confirm that the original quiz files remain listed.
- Open the original quiz's index.html in Microsoft Edge.
- Confirm that the original three-mode quiz still loads.
Nice Work!
Nice Work!
You made it! Your original three-mode Japanese vocabulary quiz remains intact beside a responsive Bilingual Form Explorer.
What you learned:
- Extended the existing quiz with a separate grammar explorer. The original three-mode experience remains unchanged.
- Built dependent dropdowns that change the Form choices with the selected category. Modeled four noun predicate states. Added five requested verb study forms. Mapped eight adjective combinations. Kept adverbs base-only.
- Rendered bilingual grammar cards from structured JavaScript data. The cards identify い-adjectives separately from な-adjectives. English guidance compares the selected forms without forcing a one-to-one mapping. Responsive styling keeps the cards readable on narrow screens. Visible focus outlines support keyboard use. A polite live region announces the changing result count.
- Secret Mission: Added a Verb group filter that narrows results to Group 1 かく, Group 2 たべる, or Group 3 する. The filter becomes available only when Verb is selected.
Ready to quiz yourself?