Tangy is building your next step
Shaping the lesson around what you want to make.
Tangy is building your next step
Shaping the lesson around what you want to make.
Computer Science
Turn your current HTML and early React experience into a small full-stack to-do app. You will keep the interface simple, add a Node.js and Express server, connect browser JavaScript to server routes, and finish with a runnable project that lets someone add, view, complete, and remove tasks.
Shape the interface and task behavior
4 lessonsStart from the learner's demonstrated HTML and CSS foundation. Build a standalone browser version first so the project has a visible interface and predictable task behavior before introducing the server runtime.
Introduce the Express server
3 lessonsCross the runtime bridge in small steps: create the Node project, run one server, then serve the already-working front end. The learner sees the same project working through Express before learning API design.
Move task data behind the API
4 lessonsReplace the browser-only task array with a deliberately small in-memory server model. Each step adds one route and immediately gives the browser a more realistic source of truth.
Connect the browser to the server
4 lessonsUse the learner's working browser interactions as the bridge into asynchronous programming. Replace local mutations one at a time with fetch calls, preserving the interface while changing its data source.
Polish, verify, and present the project
4 lessonsTurn the working prototype into a reliable portfolio-sized project. The learner checks the important paths, improves the interface details, and prepares a concise demonstration of the finished app.
Public lesson
You already know how to organize a semantic HTML page. This time, you’ll apply that same thinking inside a React component. For now, the screen only needs to look like a to-do page; behavior comes later.
Tasks
Start the React app using the command your project already uses, such as:
npm run dev
npm run dev
Open the local URL in your browser.
Tasks
Look at the current screen and identify where the main app component is defined. It is often one of these:
src/App.jsxsrc/App.jssrc/App.tsxKeep the existing imports and component setup. You’ll replace the component’s returned markup.
Your page needs these regions:
Use semantic elements so the page structure is understandable even without styling:
<main> for the page’s primary content<header> for the title and short introduction<section> for the form and task list<form> for entering a task<ul> and <li> for the tasks<label> connected to the text input<button> for actionsTasks
Before coding, decide what each section should be called. For example, the form section could be “Add a task” and the list section could be “Your tasks.”
Replace only the returned markup in your main component. The comments below are places where your page-specific JSX is still needed.
<!-- tangeble:starter -->function App() {
return (
<main className="todo-page">
{/* Add a header with the page title and a short description. */}
<section aria-labelledby="add-task-heading">
{/* Add an h2 whose id matches aria-labelledby. */}
<form>
{/* Add a label connected to the task text input. */}
{/* Add a text input with a useful name and placeholder. */}
{/* Add a submit button. */}
</form>
</section>
<section aria-labelledby="task-list-heading">
{/* Add an h2 whose id matches aria-labelledby. */}
<ul>
{/* Add two sample li elements so the page is visibly populated. */}
{/* Each task should have a checkbox, task text, and delete button. */}
</ul>
</section>
{/* Add a feedback paragraph with an accessible live-region role. */}
</main>
);
}
export default App;
function App() {
return (
<main className="todo-page">
{/* Add a header with the page title and a short description. */}
<section aria-labelledby="add-task-heading">
{/* Add an h2 whose id matches aria-labelledby. */}
<form>
{/* Add a label connected to the task text input. */}
{/* Add a text input with a useful name and placeholder. */}
{/* Add a submit button. */}
</form>
</section>
<section aria-labelledby="task-list-heading">
{/* Add an h2 whose id matches aria-labelledby. */}
<ul>
{/* Add two sample li elements so the page is visibly populated. */}
{/* Each task should have a checkbox, task text, and delete button. */}
</ul>
</section>
{/* Add a feedback paragraph with an accessible live-region role. */}
</main>
);
}
export default App;
A few JSX details matter here:
className, not class.htmlFor on a <label>, and make it match the input’s id.name.type, such as submit or button.Tasks
Do not add state or event handlers yet. Static sample tasks are enough for this lesson.
Use the stylesheet already connected to your app. If it is src/App.css, add styles that make the regions and task controls easy to distinguish.
.todo-page {
/* Set a readable width and spacing for the page. */
}
.todo-page header {
/* Add spacing below the page introduction. */
}
.todo-page section {
/* Add separation between the form and task list regions. */
}
.todo-page ul {
/* Remove the default list indentation and add vertical spacing. */
}
.todo-page li {
/* Arrange the checkbox, text, and delete button clearly. */
}
.feedback {
/* Make feedback easy to notice without overpowering the tasks. */
}
.todo-page {
/* Set a readable width and spacing for the page. */
}
.todo-page header {
/* Add spacing below the page introduction. */
}
.todo-page section {
/* Add separation between the form and task list regions. */
}
.todo-page ul {
/* Remove the default list indentation and add vertical spacing. */
}
.todo-page li {
/* Arrange the checkbox, text, and delete button clearly. */
}
.feedback {
/* Make feedback easy to notice without overpowering the tasks. */
}
Tasks
Choose simple values that fit the rest of the project. The goal is not visual polish; it should be immediately obvious where the form, list, controls, and feedback are.
Tasks
Refresh the page and verify all of the following:
Tasks
Then use the keyboard:
Tab repeatedly.Find the bug
Something's wrong — can you spot it?
If a label does not focus its input when clicked, compare the label’s htmlFor value with the input’s id. They must match exactly.
Explain it back
Put it in your own words
Open your component and ask:
20 more characters
When the browser shows a clearly organized task page and keyboard navigation reaches every control, this screen structure is ready for the next lesson.
5 modules · 19 lessons
Shape the interface and task behavior
Introduce the Express server
Move task data behind the API
Connect the browser to the server
Polish, verify, and present the project
Learn by building your own version.
Remix this public project to open the workspace, follow the guided build, and let the AI mentor teach you through the work instead of doing it for you.