diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json
index 4eae230e659..8487155bd94 100644
--- a/client/i18n/locales/english/intro.json
+++ b/client/i18n/locales/english/intro.json
@@ -6248,6 +6248,12 @@
"In this workshop, you will continue to practice working with TypeScript by building a fortune telling app."
]
},
+ "lab-flashcard-quiz-app": {
+ "title": "Build a Flashcard Quiz App",
+ "intro": [
+ "In this lab, you will practice using TypeScript by building a flashcard quiz app."
+ ]
+ },
"review-typescript": {
"title": "Typescript Review",
"intro": [
diff --git a/curriculum/challenges/english/blocks/lab-flashcard-quiz-app/69b868127999e97f1903f8e1.md b/curriculum/challenges/english/blocks/lab-flashcard-quiz-app/69b868127999e97f1903f8e1.md
new file mode 100644
index 00000000000..e00a201ec81
--- /dev/null
+++ b/curriculum/challenges/english/blocks/lab-flashcard-quiz-app/69b868127999e97f1903f8e1.md
@@ -0,0 +1,701 @@
+---
+id: 69b868127999e97f1903f8e1
+title: Build a Flashcard Quiz App
+challengeType: 25
+dashedName: lab-flashcard-quiz-app
+---
+
+# --description--
+
+In this lab, you will create an app that displays and stores flashcard data that can
+be retrieved later.
+
+**Objective:** Fulfill the user stories below and get all the tests to pass to complete the lab.
+
+**User Stories:**
+
+1) You should have an HTML element with an id of `flashcard`.
+2) You should have an interface called `FlashCard`.
+3) The `FlashCard` interface should contain the following properties `questionText` and `questionAnswer` both of type `string`.
+4) You should have a collection of `FlashCard` elements called `currentCards`.
+5) When the `#flashcard` element is clicked, the card should have the `flipped` class.
+6) You should have an element with an id of `delete-btn`.
+7) When the `#delete-btn` element is clicked, it should remove current card and display the previous card data.
+8) You should create an entry form with an id of `entry-form` to be able to add more flashcards to the `currentCards` collection on submit.
+9) The two elements inside of the form should have an id of `front-text` and `back-text` respectively.
+10) You should create and call an `InvalidUserInputError` when either the question text or question answer is empty in the entry form.
+
+# --hints--
+
+You should have an HTML element with an id of `flashcard`.
+
+```js
+const element = document.querySelector("#flashcard");
+assert.exists(element);
+```
+
+You should have a `FlashCard` interface.
+
+```js
+const explorer = await __helpers.Explorer(code);
+console.log(explorer.interfaces.FlashCard)
+assert.exists(explorer.interfaces.FlashCard);
+```
+
+The `FlashCard` interface should have a `questionText` property of type `string`.
+
+```js
+const explorer = await __helpers.Explorer(code);
+const { FlashCard } = explorer.interfaces;
+assert.isTrue(FlashCard.hasTypeProps([{ name: "questionText", type: "string" }]));
+```
+
+The `FlashCard` interface should have a `questionAnswer` property of type `string`.
+
+```js
+const explorer = await __helpers.Explorer(code);
+const { FlashCard } = explorer.interfaces;
+assert.isTrue(FlashCard.hasTypeProps([{ name: "questionAnswer", type: "string" }]));
+```
+
+You should have a collection of `FlashCard` elements called `currentCards` with the type `FlashCard[]`.
+
+```js
+const explorer = await __helpers.Explorer(code);
+assert.exists(explorer.variables.currentCards);
+assert.isTrue(explorer.variables.currentCards.annotation.matches('FlashCard[]'));
+```
+
+When the `#flashcard` element is first clicked, the element should receive the `flipped` class.
+
+```js
+const element = document.querySelector("#flashcard");
+element.click();
+assert.isTrue(element.classList.contains("flipped"));
+```
+
+You should have an element with an id of `delete-btn`.
+
+```js
+const element = document.querySelector("#flashcard");
+assert.exists(element);
+```
+
+When the `delete-btn` is clicked, a flashcard element should be removed from the `currentCards` collection.
+
+```js
+const entryForm = document.querySelector("#entry-form");
+const frontText = document.querySelector("#front-text");
+const backText = document.querySelector("#back-text");
+const deleteBtn = document.querySelector("#delete-btn");
+const flashCard = document.querySelector("#flashcard");
+const submitBtn = entryForm.querySelector("button[type='submit']");
+
+frontText.value = "Test question";
+backText.value = "Test answer";
+submitBtn.click();
+
+frontText.value = "Test question 2";
+backText.value = "Test answer 2";
+submitBtn.click();
+
+deleteBtn.click();
+assert.notInclude(flashCard.textContent, "Test question 2");
+```
+
+When the `delete-btn` is clicked, the previous flashcard data should be displayed.
+
+```js
+const entryForm = document.querySelector("#entry-form");
+const frontText = document.querySelector("#front-text");
+const backText = document.querySelector("#back-text");
+const deleteBtn = document.querySelector("#delete-btn");
+const flashCard = document.querySelector("#flashcard");
+const submitBtn = entryForm.querySelector("button[type='submit']");
+
+frontText.value = "Test Front 1";
+backText.value = "Test Back 1";
+submitBtn.click();
+
+frontText.value = "Test Front 2";
+backText.value = "Test Back 2";
+submitBtn.click();
+
+deleteBtn.click();
+assert.include(flashCard.textContent, "Test Front 1");
+assert.notInclude(flashCard.textContent, "Test Front 2");
+```
+
+You should create an entry form with an id of `entry-form`.
+
+```js
+const element = document.querySelector("#entry-form");
+assert.exists(element);
+```
+
+You should have two `textarea` elements of ids `front-text` and `back-text` respectively inside the form.
+
+```js
+const entryForm = document.querySelector("#entry-form");
+const frontText = entryForm.querySelector("#front-text");
+const backText = entryForm.querySelector("#back-text");
+
+assert.exists(frontText);
+assert.exists(backText);
+assert.equal(frontText.tagName.toLowerCase(), "textarea");
+assert.equal(backText.tagName.toLowerCase(), "textarea");
+```
+
+An `InvalidUserInputError` should be thrown when either the question text or question answer is empty in the entry form.
+
+```js
+const entryForm = document.querySelector("#entry-form");
+const frontText = document.querySelector("#front-text");
+const backText = document.querySelector("#back-text");
+const submitBtn = entryForm.querySelector("button[type='submit']");
+
+const lengthBefore = currentCards.length;
+
+frontText.value = "";
+backText.value = "Some answer";
+submitBtn.click();
+assert.strictEqual(currentCards.length, lengthBefore);
+
+frontText.value = "Some question";
+backText.value = "";
+submitBtn.click();
+assert.strictEqual(currentCards.length, lengthBefore);
+```
+
+# --seed--
+
+## --seed-contents--
+
+```html
+
+```
+
+```css
+
+```
+
+```ts
+
+```
+
+# --solutions--
+
+```html
+
+
+