Study session flow
Turn createStudySession output into a timed UI with React.
createStudySession() returns a timed agenda plus nested learning materials. Use <StudySession /> for the default runner, or build your own from blocks and materials.
What you get
import { createStudySession } from "edu-sdk";
const session = await createStudySession({
model: "google/gemini-3.6-flash",
content,
durationMinutes: 45,
difficulty: "medium",
});
const { topic, goals, tips, blocks, materials } = session.content;blocks— ordered agenda items (read,flashcards,quiz,break, …) with durations and instructions.materials— aLearningSetContentobject: nested full artifacts keyed by type (quiz,flashcards, …). May be{}if nothing was allocated.
Under the hood the SDK plans the session, then generates materials with createLearningSet.
Default: <StudySession />
import { StudySession } from "@edu-sdk/react";
import "@edu-sdk/react/styles.css";
<StudySession session={session.content} />The component owns block progress, a per-block countdown, Skip / Next / Finish, and mounts the matching material components. Customize nested materials with renderQuiz / quizProps (and the same pattern for flashcards, practice problems, study guide, and renderNotes) — see <StudySession />. You do not need a fully custom runner just to style a nested quiz or attach onComplete.
Custom runner
If you need different session UX (custom timers, forced revisit rules, etc.), walk blocks yourself and compose materials:
for (const block of blocks) {
console.log(block.title, block.durationMinutes, block.instructions);
if (block.materialKey === "quiz" && materials.quiz) {
// materials.quiz is Artifact<QuizQuestion[]>
renderQuiz(materials.quiz.content);
}
if (block.materialKey === "flashcards" && materials.flashcards) {
renderFlashcards(materials.flashcards.content);
}
// break / read / review often have no materialKey
}materialKey is only set when that material was allocated. Blocks like break or read usually have none.
import { Quiz, Flashcards, StudyGuide, PracticeProblems } from "@edu-sdk/react";
import "@edu-sdk/react/styles.css";
function SessionBlock({ block, materials }) {
switch (block.materialKey) {
case "quiz":
return materials.quiz ? (
<Quiz questions={materials.quiz.content} />
) : null;
case "flashcards":
return materials.flashcards ? (
<Flashcards flashcards={materials.flashcards.content} />
) : null;
case "practiceProblems":
return materials.practiceProblems ? (
<PracticeProblems problems={materials.practiceProblems.content} />
) : null;
case "studyGuide":
return materials.studyGuide ? (
<StudyGuide studyGuide={materials.studyGuide} />
) : null;
case "notes":
return materials.notes ? (
<article>{/* render Markdown: materials.notes.content */}</article>
) : null;
default:
return <p>{block.instructions}</p>;
}
}Remember: list UIs take .content; StudyGuide takes the full nested artifact.
What your app still owns
- Persistence of session state (even with
<StudySession />, use the callbacks) - A Markdown renderer for notes if you want more than plain text (
renderNotesor your own UI) - Nested material styling/callbacks via
*Props, or full replacement viarender*on<StudySession /> - Any UX beyond the default runner (custom timers, forced revisit rules, etc.) when you build your own
See also Concepts and createStudySession.