feat(curriculum): adding superhero application form (React forms) workshop (#59932)

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
Co-authored-by: Tom <20648924+moT01@users.noreply.github.com>
This commit is contained in:
Kolade Chris
2025-05-07 21:49:18 +01:00
committed by GitHub
parent be2fac9b61
commit b0e616a35a
25 changed files with 4413 additions and 3 deletions

View File

@@ -3539,9 +3539,11 @@
"In these lecture videos, you will learn about working with forms in React."
]
},
"sgau": {
"title": "276",
"intro": []
"workshop-superhero-application-form": {
"title": "Build a Superhero Application Form",
"intro": [
"In this workshop, you will build a superhero application form."
]
},
"lab-event-rsvp": {
"title": "Build an Event RSVP",

View File

@@ -0,0 +1,9 @@
---
title: Introduction to the Build a Superhero Application Form
block: workshop-superhero-application-form
superBlock: full-stack-developer
---
## Introduction to the Build a Superhero Application Form
This is workshop will cover how to work with forms in React.

View File

@@ -0,0 +1,97 @@
{
"name": "Build a Superhero Application Form",
"isUpcomingChange": true,
"usesMultifileEditor": true,
"hasEditableBoundaries": true,
"blockType": "workshop",
"blockLayout": "challenge-grid",
"dashedName": "workshop-superhero-application-form",
"superBlock": "full-stack-developer",
"challengeOrder": [
{
"id": "6808fe91a5cb0c3355f23027",
"title": "Step 1"
},
{
"id": "680900675ae3d54ee19590c3",
"title": "Step 2"
},
{
"id": "680fc849a6f2be0a8597c593",
"title": "Step 3"
},
{
"id": "680900675ae3d54ee19590c4",
"title": "Step 4"
},
{
"id": "680900675ae3d54ee19590c5",
"title": "Step 5"
},
{
"id": "680900675ae3d54ee19590c6",
"title": "Step 6"
},
{
"id": "680900675ae3d54ee19590c7",
"title": "Step 7"
},
{
"id": "680900675ae3d54ee19590c8",
"title": "Step 8"
},
{
"id": "680900675ae3d54ee19590c9",
"title": "Step 9"
},
{
"id": "680900675ae3d54ee19590ca",
"title": "Step 10"
},
{
"id": "680900675ae3d54ee19590cb",
"title": "Step 11"
},
{
"id": "680900675ae3d54ee19590cc",
"title": "Step 12"
},
{
"id": "680900675ae3d54ee19590cd",
"title": "Step 13"
},
{
"id": "680900675ae3d54ee19590ce",
"title": "Step 14"
},
{
"id": "68148d280ee30e5a567a0e2d",
"title": "Step 15"
},
{
"id": "680900675ae3d54ee19590cf",
"title": "Step 16"
},
{
"id": "680900675ae3d54ee19590d0",
"title": "Step 17"
},
{
"id": "68149b101d905a6fc2fcd6d8",
"title": "Step 18"
},
{
"id": "680900675ae3d54ee19590d1",
"title": "Step 19"
},
{
"id": "680900675ae3d54ee19590d2",
"title": "Step 20"
},
{
"id": "680900675ae3d54ee19590d3",
"title": "Step 21"
}
],
"helpCategory": "JavaScript"
}

View File

@@ -0,0 +1,157 @@
---
id: 6808fe91a5cb0c3355f23027
title: Step 1
challengeType: 0
dashedName: step-1
demoType: onLoad
---
# --description--
In this workshop, you'll learn how to work with forms in React by building a superhero application form.
Some boilerplate has been provided, you just need to create the rest of the React component.
Begin by returning a `div` element with a `className` of `form-wrap`. Inside the `div`, create an `h2` element with the text `Superhero Application Form`. Below that, create a `p` element with the text `Please complete all fields`.
# --hints--
You should return a `div` element with the `className` of `form-wrap`.
```js
assert.exists(document?.querySelector("div.form-wrap"));
```
You should create an `h2` element inside your `div` element.
```js
assert.exists(document?.querySelector(".form-wrap > h2"));
```
Your `h2` element should have the text `Superhero Application Form`.
```js
const h2El = document?.querySelector("h2")
assert.equal(h2El?.textContent, "Superhero Application Form");
```
You should create a `p` element inside your `div` element. Make sure it comes after the `h2`.
```js
assert.exists(document?.querySelector(".form-wrap > h2 + p"));
```
Your `p` element should have the text `Please complete all fields`.
```js
const pEl = document?.querySelector("p")
assert.equal(pEl?.textContent, "Please complete all fields");
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
--fcc-editable-region--
--fcc-editable-region--
};
```

View File

@@ -0,0 +1,196 @@
---
id: 680900675ae3d54ee19590c3
title: Step 2
challengeType: 0
dashedName: step-2
---
# --description--
Before building out the form itself, you will create the state variables you need. They are `heroName`, `realName`, `powerSource`, and `powers`.
For now, create the variables and setters for `heroName` and `realName`. Both should have an intitial value of empty strings.
# --hints--
You should use the array destructuring syntax to set a `heroName` state variable and a `setHeroName` setter.
```js
assert.match(code, /(const|let)\s+\[\s*heroName\s*,\s*setHeroName\s*\]/);
```
Your `heroName` and `setHeroName` should use the `useState` hook.
```js
async () => {
const abuseState = __helpers.spyOn(React, "useState");
const script = [...document.querySelectorAll("script")].find((s) => s.dataset.src === "index.jsx").innerText;
const exports = {};
const _a = eval(script);
const _b = await __helpers.prepTestComponent(exports.SuperheroForm);
assert.isAtLeast(abuseState.calls.length, 1);
}
```
Your `useState` hook for `heroName` should have an initial value of empty string.
```js
async () => {
const abuseState = __helpers.spyOn(React, "useState");
const script = [...document.querySelectorAll("script")].find((s) => s.dataset.src === "index.jsx").innerText;
const exports = {};
const _a = eval(script);
const _b = await __helpers.prepTestComponent(exports.SuperheroForm);
assert.equal(abuseState.calls[0]?.[0], "");
}
```
You should use the array destructuring syntax to set a `realName` state variable and a `setRealName` setter.
```js
assert.match(code, /(const|let)\s+\[\s*realName\s*,\s*setRealName\s*\]/);
```
Your `realName` and `setRealName` should use the `useState` hook.
```js
async () => {
const abuseState = __helpers.spyOn(React, "useState");
const script = [...document.querySelectorAll("script")].find((s) => s.dataset.src === "index.jsx").innerText;
const exports = {};
const _a = eval(script);
const _b = await __helpers.prepTestComponent(exports.SuperheroForm);
assert.isAtLeast(abuseState.calls.length, 2);
}
```
Your `useState` hook for `realName` should have an initial value of empty string.
```js
async () => {
const abuseState = __helpers.spyOn(React, "useState");
const script = [...document.querySelectorAll("script")].find((s) => s.dataset.src === "index.jsx").innerText;
const exports = {};
const _a = eval(script);
const _b = await __helpers.prepTestComponent(exports.SuperheroForm);
assert.equal(abuseState.calls[1]?.[0], "");
}
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
--fcc-editable-region--
--fcc-editable-region--
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
</div>
)
};
```

View File

@@ -0,0 +1,148 @@
---
id: 680900675ae3d54ee19590c4
title: Step 4
challengeType: 0
dashedName: step-4
---
# --description--
Below the paragraph, create a `form` element. Within it, add a `div` with a `className` of `section`.
# --hints--
You should create a `form` element.
```js
assert.exists(document?.querySelector("form"));
```
You should create a `div` element inside your `form` element.
```js
assert.exists(document?.querySelector("form > div"));
```
Your `div` element should have a `className` of `section`.
```js
assert.exists(document?.querySelector("form > div.section"));
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
--fcc-editable-region--
--fcc-editable-region--
</div>
)
};
```

View File

@@ -0,0 +1,162 @@
---
id: 680900675ae3d54ee19590c5
title: Step 5
challengeType: 0
dashedName: step-5
---
# --description--
Time to create the labels and inputs. In the form, create a `label` with the text `Hero Name` and an `input` element of type `text` inside it.
Connect the `input` for `Hero Name` to the `heroName` state variable by giving it a `value` attribute set to `heroName`.
# --hints--
You should create a `label` element.
```js
assert.exists(document?.querySelector("label"));
```
Your `label` element should have `Hero Name` as its text.
```js
const labelEl = document.querySelector("label")
assert.equal(labelEl?.textContent, "Hero Name");
```
You should create an `input` of type `text` element inside your `label` element.
```js
const inputEl = document.querySelector("label > input");
assert.equal(inputEl?.getAttribute("type"), "text");
```
Your `input` element should have its value set to the `heroName` state variable.
```js
assert.match(code, /value\s*=\s*\{\s*heroName\s*\}/)
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
--fcc-editable-region--
--fcc-editable-region--
</div>
</form>
</div>
)
};
```

View File

@@ -0,0 +1,151 @@
---
id: 680900675ae3d54ee19590c6
title: Step 6
challengeType: 0
dashedName: step-6
---
# --description--
You may notice you can't type in the `input`. If you open up the console you will see a warning.
To remove the warning, use the `onChange` event to update `heroName`. The value for the `onChange` event should be an arrow function with `e` for the parameter. The arrow function should implicitly return `setHeroName(e.target.value)`.
# --hints--
Your `input` element should have an `onChange` attribute.
```js
assert.match(code, /onChange\s*=\s*\{/)
```
You should use the `onChange` to set the value of the `heroName` state variable so you can type in the input field.
```js
assert.match(code, /onChange\s*=\s*\{\s*(e|\(\s*e\s*\))\s*=>\s*setHeroName\s*\(\s*e\s*\.\s*target\s*\.\s*value\s*\)\s*\}/)
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
--fcc-editable-region--
<label>
Hero Name
<input type='text' value={heroName} />
</label>
--fcc-editable-region--
</div>
</form>
</div>
)
};
```

View File

@@ -0,0 +1,177 @@
---
id: 680900675ae3d54ee19590c7
title: Step 7
challengeType: 0
dashedName: step-7
---
# --description--
Create another `label` with the text `Real Name` and an `input` of type `password` within it. Give the `input` a `value` of `realName`.
Then use the `onChange` event to update `realName` in the same way you updated `heroName`.
# --hints--
You should create a `label` element.
```js
const labels = document.querySelectorAll("label");
assert.lengthOf(labels, 2);
```
Your `label` element should have `Real Name` as its text.
```js
const labels = document.querySelectorAll("label");
assert.equal(labels[1]?.textContent.trim(), "Real Name");
```
You should create an `input` of type `password` inside your `label` element.
```js
const inputEl = document.querySelectorAll("label > input");
assert.equal(inputEl[1]?.getAttribute("type"), "password");
```
Your `input` element should have its value set to the `realName` state variable.
```js
assert.match(code, /value\s*=\s*\{\s*realName\s*\}/)
```
You should use the `onChange` event to set the value of the `realName` state variable so you can type in the `input` field.
```js
assert.match(code, /onChange\s*=\s*\{\s*(e|\(\s*e\s*\))\s*=>\s*setRealName\s*\(\s*e\s*\.\s*target\s*\.\s*value\s*\)\s*\}/)
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
--fcc-editable-region--
--fcc-editable-region--
</div>
</form>
</div>
)
};
```

View File

@@ -0,0 +1,171 @@
---
id: 680900675ae3d54ee19590c8
title: Step 8
challengeType: 0
dashedName: step-8
---
# --description--
Next, create a `label` with the `className` of `section` and `column`, and the text `How did you get your powers?`. Inside the `label`, create a `select` element.
# --hints--
You should create a `label` element with a `className` of `section` and `column`.
```js
const labelEl = document?.querySelector("label.section.column");
assert.exists(labelEl);
```
Your `label` element should have the text `How did you get your powers?`.
```js
const labelEl = document?.querySelector("label.section.column");
assert.equal(labelEl?.textContent, "How did you get your powers?")
```
You should create a `select` element inside your `label` element.
```js
const selectEl = document?.querySelector("label > select");
assert.exists(selectEl);
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
--fcc-editable-region--
--fcc-editable-region--
</form>
</div>
)
};
```

View File

@@ -0,0 +1,214 @@
---
id: 680900675ae3d54ee19590c9
title: Step 9
challengeType: 0
dashedName: step-9
---
# --description--
Inside your `select` element, you need to create options for the user to choose as their power source. The `select` should have seven options listed below:
| Power Source |
|-------------------------------|
| `Select one` |
| `Bitten by a strange creature` |
| `Radioactive exposure` |
| `Science experiment` |
| `Alien heritage ` |
| `Ancient artifact discovery` |
| `Other` |
# --hints--
Your should create the first `option` element with the text `Select one` inside your `select` element.
```js
const optionEls = document?.querySelectorAll("select > option");
assert.equal(optionEls[0]?.textContent, "Select one");
```
Your should create a second `option` element with the text `Bitten by a strange creature` inside your `select` element.
```js
const optionEls = document?.querySelectorAll("select > option");
assert.equal(optionEls[1]?.textContent, "Bitten by a strange creature");
```
Your should create a third `option` element with the text `Radioactive exposure` inside your `select` element.
```js
const optionEls = document?.querySelectorAll("select > option");
assert.equal(optionEls[2]?.textContent, "Radioactive exposure");
```
Your should create a fourth `option` element with the text `Science experiment` inside your `select` element.
```js
const optionEls = document?.querySelectorAll("select > option");
assert.equal(optionEls[3]?.textContent, "Science experiment");
```
Your should create a fifth `option` element with the text `Alien heritage` inside your `select` element.
```js
const optionEls = document?.querySelectorAll("select > option");
assert.equal(optionEls[4]?.textContent, "Alien heritage");
```
Your should create a sixth `option` element with the text `Ancient artifact discovery` inside your `select` element.
```js
const optionEls = document?.querySelectorAll("select > option");
assert.equal(optionEls[5]?.textContent, "Ancient artifact discovery");
```
Your should create a seventh `option` element with the text `Other` inside your `select` element.
```js
const optionEls = document?.querySelectorAll("select > option");
assert.equal(optionEls[6]?.textContent, "Other");
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
--fcc-editable-region--
<select>
</select>
--fcc-editable-region--
</label>
</form>
</div>
)
};
```

View File

@@ -0,0 +1,204 @@
---
id: 680900675ae3d54ee19590ca
title: Step 10
challengeType: 0
dashedName: step-10
---
# --description--
To account for the setter function, you will have to attach a `value` attribute and an `onChange` event to the `select` and a `value` attribute to each of the `option` elements.
That's a long process, right? So the best way to handle this is to have an array of the option values and map over it to create the `option` elements.
A `powerSourceOptions` array has been added at the top of your component. Give it a look.
For now, remove all the options inside the `select` element except for the first one. In the next step you will map over the array.
# --hints--
You should have the first option element in your code.
```js
const optionEl = document?.querySelectorAll("select > option");
assert.equal(optionEl[0]?.textContent, "Select one");
```
You should remove all the option elements apart from the first one.
```js
const optionEls = document?.querySelectorAll("select > option");
assert.lengthOf(optionEls, 1)
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const powerSourceOptions = [
'Bitten by a strange creature',
'Radioactive exposure',
'Science experiment',
'Alien heritage',
'Ancient artifact discovery',
'Other'
];
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
<select>
--fcc-editable-region--
<option value=''>
Select one
</option>
<option>
Bitten by a strange creature
</option>
<option>
Radioactive exposure
</option>
<option>
Science experiment
</option>
<option>
Alien heritage
</option>
<option>
Ancient artifact discovery
</option>
<option>
Other
</option>
--fcc-editable-region--
</select>
</label>
</form>
</div>
)
};
```

View File

@@ -0,0 +1,234 @@
---
id: 680900675ae3d54ee19590cb
title: Step 11
challengeType: 0
dashedName: step-11
---
# --description--
In a prior lecture video, you learned how to render a list of options using the `map()` method like this:
```jsx
function FruitList() {
const fruits = ["Apple", "Banana", "Cherry", "Date"];
return (
<ul>
{fruits.map((fruit, index) => (
<li key={`${fruit}-${index}`}>{fruit}</li>
))}
</ul>
);
}
```
Remember that the `key` must always be unique. It helps React identify which items have changed, and been added or removed.
After the first `option`, use an arrow function to map through the `powerSourceOptions` array using `source` as the parameter.
Then inside the `map()` method, create an `option` element with a `key` of `source` and a `value` of `source`. Lastly, use `{source}` to display the name of each power source in the dropdown.
# --hints--
You should map through `powerSourceOptions`.
```js
assert.match(code, /\{\s*powerSourceOptions\s*\.\s*map\s*\(/)
```
You should pass in `source` as the parameter of the map.
```js
assert.match(code, /\{\s*powerSourceOptions\s*\.\s*map\s*\(\s*(source|\(\s*source\s*\))\s*=>/)
```
You should create an `option` element with a `key` of `source` and `value` of `source`.
```js
assert.match(code, /<\s*option\s+(key\s*=\s*{\s*source\s*}\s*value\s*=\s*{\s*source\s*}|value\s*=\s*{\s*source\s*}\s*key\s*=\s*{\s*source\s*})\s*>\s*{\s*source\s*}\s*<\/\s*option\s*>/)
```
You should have a total of seven `option` elements.
```js
const optionElements = document?.querySelectorAll("option");
assert.lengthOf(optionElements, 7);
```
For the last six `option` elements, each text content should correspond to one of the power source options from the `powerSourceOptions` array.
```js
const optionElements = document?.querySelectorAll("option");
const powerSourceOptions = [
"Bitten by a strange creature",
"Radioactive exposure",
"Science experiment",
"Alien heritage",
"Ancient artifact discovery",
"Other"
];
for (let i = 0; i < powerSourceOptions.length; i++) {
const option = optionElements[i+1];
const expected = powerSourceOptions[i];
assert.strictEqual(option?.textContent, expected);
assert.strictEqual(option.value, expected);
}
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const powerSourceOptions = [
'Bitten by a strange creature',
'Radioactive exposure',
'Science experiment',
'Alien heritage',
'Ancient artifact discovery',
'Other'
];
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
<select>
<option>
Select one
</option>
--fcc-editable-region--
--fcc-editable-region--
</select>
</label>
</form>
</div>
)
};
```

View File

@@ -0,0 +1,185 @@
---
id: 680900675ae3d54ee19590cc
title: Step 12
challengeType: 0
dashedName: step-12
---
# --description--
The values of the `powerSourceOptions` now show up as the options for the `select` element.
Now, use `powerSource` as the value of the `select`. Then, add an `onChange` to set that value using the `setPowerSource` setter function and `e.target.value` like you did with the other form elements.
# --hints--
You should use `{powerSource}` as the value of the `select` element.
```js
assert.match(code, /<\s*select\s+[\s\S]*value\s*=\s*\{\s*powerSource\s*\}/)
```
You should set the value of the `select` element with `onChange` and `setPowerSource`.
```js
assert.match(code, /<\s*select\s+[\s\S]*onChange\s*=\s*\{\s*(e|\(\s*e\s*\))\s*=>\s*setPowerSource\s*\(\s*e\s*\.\s*target\s*\.\s*value\s*\)/)
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const powerSourceOptions = [
'Bitten by a strange creature',
'Radioactive exposure',
'Science experiment',
'Alien heritage',
'Ancient artifact discovery',
'Other'
];
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
--fcc-editable-region--
<select>
<option value=''>
Select one
</option>
{powerSourceOptions.map(source => (
<option key={source} value={source}>
{source}
</option>
))}
</select>
--fcc-editable-region--
</label>
</form>
</div>
)
};
```

View File

@@ -0,0 +1,188 @@
---
id: 680900675ae3d54ee19590cd
title: Step 13
challengeType: 0
dashedName: step-13
---
# --description--
The next `input` is a checkbox to mark all super hero powers that apply to the user.
Create a `label` element with a `className` of `section` and `column`, and the text of `List your powers (select all that apply):`.
# --hints--
You shold create a `label` element with a `className` of `section` and `column`.
```js
const labelEl = document?.querySelectorAll("label.section.column");
assert.equal(labelEl?.length, 2)
```
Your `label` element should have the text `List your powers (select all that apply):`.
```js
const labelEl = document?.querySelectorAll("label.section.column");
assert.equal(labelEl[1]?.textContent, "List your powers (select all that apply):")
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const powerSourceOptions = [
'Bitten by a strange creature',
'Radioactive exposure',
'Science experiment',
'Alien heritage',
'Ancient artifact discovery',
'Other'
];
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
<select value={powerSource} onChange={e => setPowerSource(e.target.value)}>
<option value=''>
Select one
</option>
{powerSourceOptions.map(source => (
<option key={source} value={source}>
{source}
</option>
))}
</select>
</label>
--fcc-editable-region--
--fcc-editable-region--
</form>
</div>
)
};
```

View File

@@ -0,0 +1,217 @@
---
id: 680900675ae3d54ee19590ce
title: Step 14
challengeType: 0
dashedName: step-14
---
# --description--
There will be six checkboxes, so it's also best to create an array for them and map through them to display them as checkboxes. For that, a `powersOptions` array has been provided for you.
Use an arrow function to map through the `powersOptions` array using parameter of `power`. Inside the map, create a `label` element with a `key` of `power`, and a text of `Hello`.
After that, you should see six `Hello` text. You will fill in the elements of the array in the next step.
# --hints--
You should map through `powersOptions`.
```js
assert.match(code, /\{\s*powersOptions\s*\.\s*map\s*\(/)
```
You should use `power` as the parameter of your map.
```js
assert.match(code, /{\s*powersOptions\s*\.\s*map\s*\(\s*(power|\(\s*power\s*\))\s*=>/)
```
You should create a `label` element with a `key` of `power`.
```js
assert.match(code, /\{\s*powersOptions\s*\.\s*map\s*\([\s\S]*<\s*label\s+key\s*=\s*\{\s*power\s*\}\s*>[\s\S]*<\s*\/\s*label\s*>/)
```
Your `label` element should have the text `Hello`.
```js
const labelEls = document?.querySelectorAll("label")
const targetLabelEls = Array.from(labelEls).slice(4)
for (const label of targetLabelEls) {
assert.equal(label.textContent, "Hello");
}
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const powerSourceOptions = [
'Bitten by a strange creature',
'Radioactive exposure',
'Science experiment',
'Alien heritage',
'Ancient artifact discovery',
'Other'
];
const powersOptions = [
'Super Strength',
'Super Speed',
'Flight',
'Invisibility',
'Telekinesis',
'Other'
];
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
<select value={powerSource} onChange={e => setPowerSource(e.target.value)}>
<option value=''>
Select one
</option>
{powerSourceOptions.map(source => (
<option key={source} value={source}>
{source}
</option>
))}
</select>
</label>
<label className='section column'>
List your powers (select all that apply):
--fcc-editable-region--
--fcc-editable-region--
</label>
</form>
</div>
)
};
```

View File

@@ -0,0 +1,208 @@
---
id: 680900675ae3d54ee19590cf
title: Step 16
challengeType: 0
dashedName: step-16
---
# --description--
To mark the checkboxes, add a `checked` attribute to the checkbox `input`. Use the `includes` method to verify if the current `power` is in the `powers` array.
The `onChange` will be a separate function, set it to `handlePowersChange` for now. This will lead to an error you will fix in the next step.
# --hints--
You should set the checkbox `checked` state to reflect whether the current `power` value exists in the powers array.
```js
assert.match(code, /checked\s*=\s*\{\s*powers\s*\.\s*includes\s*\(\s*power\s*\)\s*\}/)
```
You should set the checkbox `onChange` attribute to `{handlePowersChange}`.
```js
assert.match(code, /onChange\s*=\s*\{\s*handlePowersChange\s*\}/)
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const powerSourceOptions = [
'Bitten by a strange creature',
'Radioactive exposure',
'Science experiment',
'Alien heritage',
'Ancient artifact discovery',
'Other'
];
const powersOptions = [
'Super Strength',
'Super Speed',
'Flight',
'Invisibility',
'Telekinesis',
'Other'
];
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
<select value={powerSource} onChange={e => setPowerSource(e.target.value)}>
<option value=''>
Select one
</option>
{powerSourceOptions.map(source => (
<option key={source} value={source}>
{source}
</option>
))}
</select>
</label>
<label className='section column'>
List your powers (select all that apply):
{powersOptions.map(power => (
<label key={power}>
--fcc-editable-region--
<input
type='checkbox'
value={power}
/>
--fcc-editable-region--
<span>{power}</span>
</label>
))}
</label>
</form>
</div>
)
};
```

View File

@@ -0,0 +1,211 @@
---
id: 680900675ae3d54ee19590d0
title: Step 17
challengeType: 0
dashedName: step-17
---
# --description--
To fix the error, create a `handlePowersChange` arrow function with an `e` parameter.
Inside the function, destructure `value` and `checked` from `e.target` to get the value of the checkbox and whether it is checked or not.
# --hints--
You should create an `handlePowersChange` function with an `e` parameter.
```js
assert.match(code, /(const|let)\s+handlePowersChange\s*=\s*(e|\(\s*e\s*\))\s*=>\s*{/)
```
You should destructure `value` and `checked` from `e.target`.
```js
assert.match(code, /(const|let)\s+handlePowersChange\s*=\s*(e|\(\s*e\s*\))\s*=>\s*{\s*(const|let)\s*{\s*(value\s*,\s*checked|checked\s*,\s*value)\s*}\s*=\s*e\s*\.\s*target/)
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const powerSourceOptions = [
'Bitten by a strange creature',
'Radioactive exposure',
'Science experiment',
'Alien heritage',
'Ancient artifact discovery',
'Other'
];
const powersOptions = [
'Super Strength',
'Super Speed',
'Flight',
'Invisibility',
'Telekinesis',
'Other'
];
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
--fcc-editable-region--
--fcc-editable-region--
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
<select value={powerSource} onChange={e => setPowerSource(e.target.value)}>
<option value=''>
Select one
</option>
{powerSourceOptions.map(source => (
<option key={source} value={source}>
{source}
</option>
))}
</select>
</label>
<label className='section column'>
List your powers (select all that apply):
{powersOptions.map(power => (
<label key={power}>
<input
type='checkbox'
value={power}
checked={powers.includes(power)}
onChange={handlePowersChange}
/>
<span>{power}</span>
</label>
))}
</label>
</form>
</div>
)
};
```

View File

@@ -0,0 +1,216 @@
---
id: 680900675ae3d54ee19590d1
title: Step 19
challengeType: 0
dashedName: step-19
---
# --description--
Next, tell the form how to submit. Add a `method` attribute with a value of `post` and an `action` attribute with a value of `https://superhero-application-form.freecodecamp.org` to the form element.
Now, submitting form will send it to that URL. You will do that in the next step.
# --hints--
Your `form` element should have a `method` attribute set to `post`.
```js
const formEl = document?.querySelector("form")
assert.equal(formEl?.getAttribute("method"), "post")
```
Your `form` elmement should have an `action` attribute set to `https://superhero-application-form.freecodecamp.org`.
```js
const formEl = document?.querySelector("form")
assert.equal(formEl?.getAttribute("action"), "https://superhero-application-form.freecodecamp.org")
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const powerSourceOptions = [
'Bitten by a strange creature',
'Radioactive exposure',
'Science experiment',
'Alien heritage',
'Ancient artifact discovery',
'Other'
];
const powersOptions = [
'Super Strength',
'Super Speed',
'Flight',
'Invisibility',
'Telekinesis',
'Other'
];
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
const handlePowersChange = e => {
const { value, checked } = e.target;
setPowers(checked ? [...powers, value] : powers.filter(p => p !== value));
}
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
--fcc-editable-region--
<form>
--fcc-editable-region--
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
<select value={powerSource} onChange={e => setPowerSource(e.target.value)}>
<option value=''>
Select one
</option>
{powerSourceOptions.map(source => (
<option key={source} value={source}>
{source}
</option>
))}
</select>
</label>
<label className='section column'>
List your powers (select all that apply):
{powersOptions.map(power => (
<label key={power}>
<input
type='checkbox'
value={power}
checked={powers.includes(power)}
onChange={handlePowersChange}
/>
<span>{power}</span>
</label>
))}
</label>
</form>
</div>
)
};
```

View File

@@ -0,0 +1,222 @@
---
id: 680900675ae3d54ee19590d2
title: Step 20
challengeType: 0
dashedName: step-20
---
# --description--
Create a `button` element with the `className` of `submit-btn` and a `type` of `submit`. Give the button the text `Join the League`.
After you do that, try to submit the form and see what happens.
# --hints--
You should create a `button` element.
```js
assert.exists(document.querySelector("button"));
```
Your button element should have a `className` attribute set to `submit-btn`.
```js
assert.exists(document.querySelector("button.submit-btn"));
```
Your `button` element should have `Join the League` as its text.
```js
const btnEl = document.querySelector("button")
assert.equal(btnEl.textContent, "Join the League");
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const powerSourceOptions = [
'Bitten by a strange creature',
'Radioactive exposure',
'Science experiment',
'Alien heritage',
'Ancient artifact discovery',
'Other'
];
const powersOptions = [
'Super Strength',
'Super Speed',
'Flight',
'Invisibility',
'Telekinesis',
'Other'
];
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
const handlePowersChange = e => {
const { value, checked } = e.target;
setPowers(checked ? [...powers, value] : powers.filter(p => p !== value));
}
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form method='post' action='https://superhero-application-form.freecodecamp.org'>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
<select value={powerSource} onChange={e => setPowerSource(e.target.value)}>
<option value=''>
Select one
</option>
{powerSourceOptions.map(source => (
<option key={source} value={source}>
{source}
</option>
))}
</select>
</label>
<label className='section column'>
List your powers (select all that apply):
{powersOptions.map(power => (
<label key={power}>
<input
type='checkbox'
value={power}
checked={powers.includes(power)}
onChange={handlePowersChange}
/>
<span>{power}</span>
</label>
))}
</label>
--fcc-editable-region--
--fcc-editable-region--
</form>
</div>
)
};
```

View File

@@ -0,0 +1,424 @@
---
id: 680900675ae3d54ee19590d3
title: Step 21
challengeType: 0
dashedName: step-21
---
# --description--
Did you notice that you can submit the form without filling in the inputs?
To stop that, add the `disabled` attribute to disable the submit button if `heroName`, `realName`, or `powerSource` are falsy, or if the length of `powers` is `0`.
Now, the button will be disabled if something isn't filled in. Fill in the form with your superhero information and submit it to join the league.
With that, you superhero application form is complete.
# --hints--
You should not modify the existing content of the button.
```js
assert.match(code, /<\s*button\s+className\s*=\s*('|")\s*submit-btn\s*\1\s*type\s*=\s*('|")\s*submit\s*\2/)
```
Your `button` element should have a `disabled` property.
```js
assert.match(code, /<\s*button\s+className\s*=\s*('|")\s*submit-btn\s*\1\s*type\s*=\s*('|")\s*submit\s*\2\s*disabled/)
```
You should disable the `button` if any of `heroName`, `realName`, and `powerSource` is false, or if the length of `powers` is `0`.
```js
assert.match(code, /disabled\s*=\s*\{\s*(?:!heroName\s*\|\|\s*!realName\s*\|\|\s*!powerSource\s*\|\|\s*powers\.length\s*===\s*0|!heroName\s*\|\|\s*!realName\s*\|\|\s*powers\.length\s*===\s*0\s*\|\|\s*!powerSource|!heroName\s*\|\|\s*!powerSource\s*\|\|\s*!realName\s*\|\|\s*powers\.length\s*===\s*0|!heroName\s*\|\|\s*!powerSource\s*\|\|\s*powers\.length\s*===\s*0\s*\|\|\s*!realName|!heroName\s*\|\|\s*powers\.length\s*===\s*0\s*\|\|\s*!realName\s*\|\|\s*!powerSource|!heroName\s*\|\|\s*powers\.length\s*===\s*0\s*\|\|\s*!powerSource\s*\|\|\s*!realName|!realName\s*\|\|\s*!heroName\s*\|\|\s*!powerSource\s*\|\|\s*powers\.length\s*===\s*0|!realName\s*\|\|\s*!heroName\s*\|\|\s*powers\.length\s*===\s*0\s*\|\|\s*!powerSource|!realName\s*\|\|\s*!powerSource\s*\|\|\s*!heroName\s*\|\|\s*powers\.length\s*===\s*0|!realName\s*\|\|\s*!powerSource\s*\|\|\s*powers\.length\s*===\s*0\s*\|\|\s*!heroName|!realName\s*\|\|\s*powers\.length\s*===\s*0\s*\|\|\s*!heroName\s*\|\|\s*!powerSource|!realName\s*\|\|\s*powers\.length\s*===\s*0\s*\|\|\s*!powerSource\s*\|\|\s*!heroName|!powerSource\s*\|\|\s*!heroName\s*\|\|\s*!realName\s*\|\|\s*powers\.length\s*===\s*0|!powerSource\s*\|\|\s*!heroName\s*\|\|\s*powers\.length\s*===\s*0\s*\|\|\s*!realName|!powerSource\s*\|\|\s*!realName\s*\|\|\s*!heroName\s*\|\|\s*powers\.length\s*===\s*0|!powerSource\s*\|\|\s*!realName\s*\|\|\s*powers\.length\s*===\s*0\s*\|\|\s*!heroName|!powerSource\s*\|\|\s*powers\.length\s*===\s*0\s*\|\|\s*!heroName\s*\|\|\s*!realName|!powerSource\s*\|\|\s*powers\.length\s*===\s*0\s*\|\|\s*!realName\s*\|\|\s*!heroName|powers\.length\s*===\s*0\s*\|\|\s*!heroName\s*\|\|\s*!realName\s*\|\|\s*!powerSource|powers\.length\s*===\s*0\s*\|\|\s*!heroName\s*\|\|\s*!powerSource\s*\|\|\s*!realName|powers\.length\s*===\s*0\s*\|\|\s*!realName\s*\|\|\s*!heroName\s*\|\|\s*!powerSource|powers\.length\s*===\s*0\s*\|\|\s*!realName\s*\|\|\s*!powerSource\s*\|\|\s*!heroName|powers\.length\s*===\s*0\s*\|\|\s*!powerSource\s*\|\|\s*!heroName\s*\|\|\s*!realName|powers\.length\s*===\s*0\s*\|\|\s*!powerSource\s*\|\|\s*!realName\s*\|\|\s*!heroName)\s*\}/)
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const powerSourceOptions = [
'Bitten by a strange creature',
'Radioactive exposure',
'Science experiment',
'Alien heritage',
'Ancient artifact discovery',
'Other'
];
const powersOptions = [
'Super Strength',
'Super Speed',
'Flight',
'Invisibility',
'Telekinesis',
'Other'
];
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
const handlePowersChange = e => {
const { value, checked } = e.target;
setPowers(checked ? [...powers, value] : powers.filter(p => p !== value));
}
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form method='post' action='https://superhero-application-form.freecodecamp.org'>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
<select value={powerSource} onChange={e => setPowerSource(e.target.value)}>
<option value=''>
Select one
</option>
{powerSourceOptions.map(source => (
<option key={source} value={source}>
{source}
</option>
))}
</select>
</label>
<label className='section column'>
List your powers (select all that apply):
{powersOptions.map(power => (
<label key={power}>
<input
type='checkbox'
value={power}
checked={powers.includes(power)}
onChange={handlePowersChange}
/>
<span>{power}</span>
</label>
))}
</label>
--fcc-editable-region--
<button
className='submit-btn'
type='submit'
>
Join the League
</button>
--fcc-editable-region--
</form>
</div>
)
};
```
# --solutions--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const powerSourceOptions = [
'Bitten by a strange creature',
'Radioactive exposure',
'Science experiment',
'Alien heritage',
'Ancient artifact discovery',
'Other'
];
const powersOptions = [
'Super Strength',
'Super Speed',
'Flight',
'Invisibility',
'Telekinesis',
'Other'
];
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
const handlePowersChange = e => {
const { value, checked } = e.target;
setPowers(checked ? [...powers, value] : powers.filter(p => p !== value));
}
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form method='post' action='https://superhero-application-form.freecodecamp.org'>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
<select value={powerSource} onChange={e => setPowerSource(e.target.value)}>
<option value=''>
Select one
</option>
{powerSourceOptions.map(source => (
<option key={source} value={source}>
{source}
</option>
))}
</select>
</label>
<label className='section column'>
List your powers (select all that apply):
{powersOptions.map(power => (
<label key={power}>
<input
type='checkbox'
value={power}
checked={powers.includes(power)}
onChange={handlePowersChange}
/>
<span>{power}</span>
</label>
))}
</label>
<button
className='submit-btn'
type='submit'
disabled={
!heroName || !realName || !powerSource || powers.length === 0
}
>
Join the League
</button>
</form>
</div>
)
};
```

View File

@@ -0,0 +1,198 @@
---
id: 680fc849a6f2be0a8597c593
title: Step 3
challengeType: 0
dashedName: step-3
---
# --description--
Now, create the state variables and setters for `powerSource` and `powers`. `powerSource` should have an initial value of empty string, and `powers` should have an initial value of an empty array.
# --hints--
You should use array destructuring to set a `powerSource` state variable and a `setPowerSource` setter.
```js
assert.match(code, /(const|let)\s+\[\s*powerSource\s*,\s*setPowerSource\s*\]/);
```
Your `powerSource` and `setPowerSource` should use the `useState` hook.
```js
async () => {
const abuseState = __helpers.spyOn(React, "useState");
const script = [...document.querySelectorAll("script")].find((s) => s.dataset.src === "index.jsx").innerText;
const exports = {};
const _a = eval(script);
const _b = await __helpers.prepTestComponent(exports.SuperheroForm);
assert.isAtLeast(abuseState.calls.length, 3);
}
```
Your `useState` hook for `powerSource` should have an initial value of empty string.
```js
async () => {
const abuseState = __helpers.spyOn(React, "useState");
const script = [...document.querySelectorAll("script")].find((s) => s.dataset.src === "index.jsx").innerText;
const exports = {};
const _a = eval(script);
const _b = await __helpers.prepTestComponent(exports.SuperheroForm);
assert.equal(abuseState.calls[2]?.[0], "");
}
```
You should use array destructuring to set a `powers` state variable and a `setPowers` setter.
```js
assert.match(code, /(const|let)\s+\[\s*powers\s*,\s*setPowers\s*\]/);
```
Your `powers` and `setPowers` should use the `useState` hook.
```js
async () => {
const abuseState = __helpers.spyOn(React, "useState");
const script = [...document.querySelectorAll("script")].find((s) => s.dataset.src === "index.jsx").innerText;
const exports = {};
const _a = eval(script);
const _b = await __helpers.prepTestComponent(exports.SuperheroForm);
assert.isAtLeast(abuseState.calls.length, 4);
}
```
Your `useState` hook for `powers` should have an initial value of empty array.
```js
async () => {
const abuseState = __helpers.spyOn(React, "useState");
const script = [...document.querySelectorAll("script")].find((s) => s.dataset.src === "index.jsx").innerText;
const exports = {};
const _a = eval(script);
const _b = await __helpers.prepTestComponent(exports.SuperheroForm);
console.log("State calls:", abuseState.calls)
assert.deepEqual(abuseState.calls[3]?.[0], []);
}
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
--fcc-editable-region--
--fcc-editable-region--
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
</div>
)
};
```

View File

@@ -0,0 +1,208 @@
---
id: 68148d280ee30e5a567a0e2d
title: Step 15
challengeType: 0
dashedName: step-15
---
# --description--
Remove the `Hello` text inside the `label`, then create an `input` of type `checkbox` and a `value` of `power`.
Finally, display the values from the array next to each checkbox by creating a `span` element just before the closing `label` with a text content of `{power}`.
# --hints--
You should remove the `Hello` text from the `label` element.
```js
assert.notMatch(code, /hello/i)
```
You should create an `input` with its `type` set to `checkbox` and a `value` set to `power` as the first child of the label.
```js
assert.match(code, /<\s*label\s+key\s*=\s*{\s*power\s*}\s*>\s*<\s*input\s+type\s*=\s*("|')checkbox\1\s*value\s*=\s*\{\s*power\s*\}\s*\/>[\s\S]*<\/\s*label\s*>/)
```
You should create a `span` element with `{power}` for its text content as the last child of the label.
```js
assert.match(code, /<\s*label\s+key\s*=\s*{\s*power\s*}\s*>[\s\S]*<\s*span\s*>\s*{\s*power\s*}\s*<\/\s*span\s*>\s*<\/\s*label\s*>/)
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const powerSourceOptions = [
'Bitten by a strange creature',
'Radioactive exposure',
'Science experiment',
'Alien heritage',
'Ancient artifact discovery',
'Other'
];
const powersOptions = [
'Super Strength',
'Super Speed',
'Flight',
'Invisibility',
'Telekinesis',
'Other'
];
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
<select value={powerSource} onChange={e => setPowerSource(e.target.value)}>
<option value=''>
Select one
</option>
{powerSourceOptions.map(source => (
<option key={source} value={source}>
{source}
</option>
))}
</select>
</label>
<label className='section column'>
List your powers (select all that apply):
--fcc-editable-region--
{powersOptions.map(power => (
<label key={power}>
Hello
</label>
))}
--fcc-editable-region--
</label>
</form>
</div>
)
};
```

View File

@@ -0,0 +1,208 @@
---
id: 68149b101d905a6fc2fcd6d8
title: Step 18
challengeType: 0
dashedName: step-18
---
# --description--
Below the destructured `value` and `checked`, call the `setPowers` function to update the list of checked powers.
The function needs an array argument. In the function parameter, use a ternary operator to check if `checked` is true. If it is, spread in the existing `powers` array into a new array and add the `value` to it. If it is not true, filter out the `value` from `powers` with `powers.filter(p => p !== value)`.
# --hints--
You should use a ternary operator to check if `checked` is true. If it is, spread in the existing `powers` and `value` into an array. If it is not, filter out the `value` from `powers`.
```js
assert.match(code, /(const|let)\s*{\s*(value\s*,\s*checked|checked\s*,\s*value)\s*}\s*=\s*e\s*\.\s*target\s*;?\s*setPowers\s*\(\s*checked\s*\?\s*\[\s*\.\.\.powers\s*,\s*value\s*\]\s*:\s*powers\s*\.\s*filter\s*\(\s*(p|\(\s*p\s*\))\s*=>\s*p\s*!==?\s*value\s*\)\s*\)/)
```
# --seed--
## --seed-contents--
```html
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>Superhero Application Form</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.3/babel.min.js"></script>
<script
data-plugins="transform-modules-umd"
type="text/babel"
src="index.jsx"
></script>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div id="root"></div>
<script
data-plugins="transform-modules-umd"
type="text/babel"
data-presets="react"
data-type="module"
>
import { SuperheroForm } from './index.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(<SuperheroForm />);
</script>
</body>
</html>
```
```css
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(30deg, #ff9999 50%, #6699ff 50%)
}
.form-wrap {
background-color: white;
width: 400px;
padding: 20px;
border: 1px solid black;
box-shadow: 5px 5px 10px black;
}
.form-wrap h2,
.form-wrap p {
text-align: center;
}
.form-wrap p {
position: relative;
top: -18px;
}
.section {
display: flex;
margin-bottom: 30px;
}
.column {
flex-direction: column;
}
.submit-wrap {
text-align: center;
}
.submit-btn {
display: block;
margin: 0 auto;
padding: 0.4rem 0.5rem;
border: 1px solid black
}
.submit-btn:hover {
cursor: pointer;
background-color: #f3f3f3;
}
.submit-btn:disabled {
cursor: not-allowed;
}
```
```jsx
const { useState } = React;
export const SuperheroForm = () => {
const powerSourceOptions = [
'Bitten by a strange creature',
'Radioactive exposure',
'Science experiment',
'Alien heritage',
'Ancient artifact discovery',
'Other'
];
const powersOptions = [
'Super Strength',
'Super Speed',
'Flight',
'Invisibility',
'Telekinesis',
'Other'
];
const [heroName, setHeroName] = useState('');
const [realName, setRealName] = useState('');
const [powerSource, setPowerSource] = useState('');
const [powers, setPowers] = useState([]);
--fcc-editable-region--
const handlePowersChange = e => {
const { value, checked } = e.target;
}
--fcc-editable-region--
return (
<div className='form-wrap'>
<h2>Superhero Application Form</h2>
<p>Please complete all fields</p>
<form>
<div className='section'>
<label>
Hero Name
<input
type='text'
value={heroName}
onChange={e => setHeroName(e.target.value)}
/>
</label>
<label>
Real Name
<input
type='password'
value={realName}
onChange={e => setRealName(e.target.value)}
/>
</label>
</div>
<label className='section column'>
How did you get your powers?
<select value={powerSource} onChange={e => setPowerSource(e.target.value)}>
<option value=''>
Select one
</option>
{powerSourceOptions.map(source => (
<option key={source} value={source}>
{source}
</option>
))}
</select>
</label>
<label className='section column'>
List your powers (select all that apply):
{powersOptions.map(power => (
<label key={power}>
<input
type='checkbox'
value={power}
checked={powers.includes(power)}
onChange={handlePowersChange}
/>
<span>{power}</span>
</label>
))}
</label>
</form>
</div>
)
};
```

View File

@@ -1078,6 +1078,9 @@
{
"dashedName": "quiz-react-state-and-hooks"
},
{
"dashedName": "workshop-superhero-application-form"
},
{
"dashedName": "lecture-working-with-forms-in-react"
},