If you are a teacher, a professor, a district-IT lead, or an independent founder shipping software into a K-12 or higher-ed classroom, Chakra UI is the React component library that gives you accessibility on day one without hiring a designer. The audience is specific. A primary-school teacher building a sight-words app for her own first-graders has different needs than a high-school computer-science teacher building a quiz tool for AP CS Principles, and both of them are different from the parent of a special-needs student who is writing a homework-tracker the school will actually use. All three of them are in the search query "chakra ui tutorial for teachers," and all three of them need the same three things: components that pass a Section 508 / WCAG 2.1 AA review, a theme system that serves at least three audiences (student, teacher, parent) inside one app, and a learning curve short enough that a person who teaches full-time can still ship a working product on a Saturday. This guide is that.
Chakra UI for teachers: compliance + UX checklist
| Edu-software requirement | Chakra primitive that fits | Why it matters in a school context | Risk if you skip it |
|---|---|---|---|
| WCAG 2.1 AA conformance for procurement | Every Chakra component ships with ARIA defaults, focus-visible, keyboard nav | School-district procurement requests a VPAT and asks for WCAG 2.1 AA conformance language before purchase | Catalog rejection; the district will not buy the product |
| Section 508 readiness (federally-funded schools) | Built-in semantic HTML + ARIA on <Button>, <Dialog>, <Menu>, <Tabs>, <Alert> | Title II ADA and Section 508 apply to federally-funded districts and to many state agencies | The product cannot be used in a federally-funded school |
| Kid-friendly contrast for elementary | Chakra colorPalette + custom theme tokens; tap targets via Button size="lg" (≥44 px) | Younger eyes track high-contrast better; small fingers miss small buttons | Frustrated kids, parents complain, the teacher pulls the tool |
| Parent-portal readability | High-contrast tokens + fontSize scaling on the parent theme override | A parent reading a report card at 9 pm on a phone needs 16-18 px body and clean contrast | Parents cannot read the report; teacher gets the call instead of an email |
| Locked-state quiz UI | Tabs disabled until "Begin", Alert for timeout, Collapsible for reveal | A quiz that lets a student peek at the next question before the timer starts is not a quiz | Test integrity loss, complaints from administrators |
| Roster + gradebook density | Table with size="sm", sticky header, virtualization for 200+ students | A homeroom gradebook with 30 students per period across 6 periods is 180 rows | Teacher cannot find the row she wants in a parent conference |
| Audience-segmented theming | extendTheme with three overrides: elementary, middle / high school, parent portal | One product, three audiences, one Chakra theme system | Visual chaos; the parent portal looks like the student app |
| Dark mode for a night-study tool | Chakra ColorMode + ColorModeScript for SSR-correct first paint | Older students study at night; bright UIs cause eye strain | The student drops the tool for a darker competitor |
| Accessibility-audit handoff to school IT | A README + a manual-audit checklist + axe / Lighthouse export | A district IT lead will run their own audit; the builder needs to make that easy | The contract stalls in IT review |
| Free, MIT-licensed for a school product | Chakra UI is MIT; commercial use, redistribution, and modification all allowed | Schools and parents-as-founders cannot afford per-seat licensing on a side project | The project never ships; the teacher quits |
The honest math: Chakra UI is a free, MIT-licensed React component library that ships with WAI-ARIA defaults, semantic HTML, keyboard navigation, and a theming system that can serve a kindergartner and her grandfather inside one product. None of this makes a finished edu-software product Section 508 conformant on its own. Conformance is a property of the whole product (content, semantics, keyboard navigation, screen-reader behavior, color contrast end-to-end, document structure) and a VPAT is a sworn statement about that whole product. The component library can pay off the largest single line item on the audit. The rest of the audit is the builder's job. This guide names both halves.
Why Chakra UI fits edu-software specifically
The edu-software SERP is full of design-agency articles on "what color a learning app should be" and "what motivates Gen-Z students." Almost none of those articles names a React component library. That is convenient if you are still picking one and unhelpful if you have already committed to React and need to know which component library survives a district procurement review.
Chakra UI's case for a teacher-builder comes down to four properties.
First, accessibility-by-default. Every interactive Chakra component ships with the ARIA attributes, focus management, and keyboard handlers that WCAG 2.1 AA requires. The <Button> has the right role, the <Dialog> traps focus, the <Tabs> supports arrow-key navigation, the <Menu> announces correctly to a screen reader. For a teacher who has never written a role attribute by hand and does not want to learn how, starting from a component library where the accessibility work is mostly done is the difference between a finished product and a never-shipped project.
Second, theming for multiple audiences inside one app. Chakra's extendTheme (v3) and extendBaseTheme (v2) let you override colors, spacing, fonts, and component defaults in one config object. An edu product almost always has at least three audiences (the student who takes the quiz, the teacher who builds the quiz, and the parent who reads the report). Each audience has different visual needs (a first-grader needs bigger buttons and brighter colors; the teacher needs density to see her whole roster; the parent needs high contrast and large body text). Chakra lets you swap themes per route or per layout without rebuilding components.
Third, low CSS-skill required. Chakra's prop-based styling means a teacher who has never opened a CSS file can write <Button size="lg" colorPalette="green">Start Quiz</Button> and get a button that is the right size, the right color, has hover and focus states, is keyboard-accessible, and works in dark mode. The teacher is not learning Flexbox; she is composing components with props. The trade-off in pure design control is real and is worth it for the first version of a product that has to ship before September.
Fourth, free and MIT-licensed. A teacher-builder is rarely funded. A parent-of-special-needs-student building a tool the school will use is even more rarely funded. Chakra UI is free for commercial use, modification, and redistribution under the MIT license. There is no per-seat fee, no school-tier upcharge, no surprise invoice when the district enrolls 800 students. The license is not the differentiator on its own (MUI, Mantine, and Ant Design are all MIT or similar), but it is a precondition.
For balance: Chakra is not the only credible pick. Material UI (MUI) has a deeper data-density story (its DataGrid Pro is the right choice for a 50,000-row student data warehouse, but it costs per-developer-per-year). Mantine has excellent developer experience and is gaining traction in education side-projects. Ant Design is heavy and feels enterprise-y, which can be a wrong tone for a kid-facing app. Carbon from IBM is purpose-built for enterprise interfaces but is smaller in the React ecosystem. For most teacher-builders in 2026, the realistic short list is Chakra, MUI, or Mantine. Chakra wins on the combination of accessibility-by-default plus theming ergonomics plus zero pricing surprises. The compliance sibling page on Material UI for healthcare app builders is worth reading if your edu-product crosses into student-health territory, because the HIPAA-aware patterns map almost one-to-one onto the FERPA-aware patterns you need on the student side.
Chakra v3 vs v2 in 2026: which do you pick for an edu build
Chakra UI v3 shipped in late 2024 and is the default for a new project in 2026. Chakra v2 is still maintained for an existing codebase. The version question is real for a teacher-builder because most SERP-indexed tutorials still teach v2, and a builder who follows a 2022 YouTube tutorial in 2026 installs legacy peers and writes Provider code that no longer matches the live docs.
Decision criteria for an edu-software project:
- New project starting this week. Install v3. The current docs on chakra-ui.com are v3. The community Discord answers questions in v3. The recipe library on the Chakra site assumes v3. Starting on v2 in 2026 means migrating in 2027.
- Existing v2 codebase that already works. Stay on v2 until you have a reason to migrate. v2 is still patched and the migration is non-trivial (the styling engine moved from Emotion to Panda CSS; component APIs changed; the Provider model changed). If your gradebook ships in September, the migration is not the September project.
- A tutorial corpus the builder is following. If you are learning Chakra from a 2022 book or a 2023 video course, the tutorial is v2. Either learn v3 from the official docs and stop following the legacy tutorial, or stay on v2 for the duration of the tutorial and migrate later.
- A school-district contract pending. Both v2 and v3 produce WCAG 2.1 AA-conformant components; the version choice does not change the procurement outcome.
Install commands for both:
# Chakra UI v3 — the default for a new project in 2026
npm install @chakra-ui/react @emotion/react
# Optional: the snippet CLI generates the Provider component for you
npx @chakra-ui/cli snippet add provider
# Chakra UI v2 — for an existing project or a v2-locked tutorial
npm install @chakra-ui/react@^2 @emotion/react @emotion/styled framer-motionNote the difference: v3 dropped @emotion/styled and framer-motion as required peers. If a 2022 tutorial tells you to install both, you are on a v2 path and the rest of the tutorial will not match the v3 docs.
Set up Chakra for an edu product: extendTheme for school-district branding
The first file in a new edu-product is the theme. Here is a working v3 theme override that supports three audiences inside one app:
// src/theme.ts — Chakra UI v3 base theme + three audience overrides
import { createSystem, defaultConfig, defineConfig } from '@chakra-ui/react'
const config = defineConfig({
theme: {
tokens: {
colors: {
// Brand palette — replace with the school or district colors
brand: {
50: { value: '#E6F3FF' },
100: { value: '#BFDEFF' },
500: { value: '#1565C0' }, // Primary district blue, contrast-checked against white
700: { value: '#0D47A1' },
900: { value: '#072F6B' },
},
// Kid-friendly accents for elementary
kid: {
green: { value: '#43A047' },
orange: { value: '#FB8C00' },
purple: { value: '#8E24AA' },
},
},
fonts: {
body: { value: '"Atkinson Hyperlegible", "Inter", system-ui, sans-serif' },
heading: { value: '"Atkinson Hyperlegible", "Inter", system-ui, sans-serif' },
},
},
semanticTokens: {
colors: {
// Per-audience contrast-pair tokens. axe-core verifies each pair at AA.
elementaryBg: { value: { base: '{colors.kid.purple}', _dark: '{colors.brand.900}' } },
elementaryFg: { value: { base: 'white', _dark: 'white' } },
secondaryBg: { value: { base: '{colors.brand.500}', _dark: '{colors.brand.700}' } },
secondaryFg: { value: { base: 'white', _dark: 'white' } },
parentBg: { value: { base: 'white', _dark: '#1E1E1E' } },
parentFg: { value: { base: '#1A1A1A', _dark: '#F5F5F5' } },
},
},
},
})
export const system = createSystem(defaultConfig, config)Three deliberate choices in that theme:
- Atkinson Hyperlegible as the body font. Atkinson Hyperlegible is a free font designed by the Braille Institute specifically to maximize legibility for low-vision readers. For an edu product whose audience includes children learning to read and parents with age-related macular changes, the font choice is not cosmetic.
- Audience-named semantic tokens. Instead of
primary/secondary, the tokens are namedelementaryBg,secondaryBg,parentBg. A teacher reading the codebase six months later sees which token is for which audience without opening the design doc. - Both modes pre-defined for every token. Every contrast pair is defined for both base and
_darkmodes. The night-study app and the morning-classroom app run on the same theme.
The provider, then. v3 reads the system object via a Provider component the CLI generates:
// src/components/ui/provider.tsx — generated by `npx @chakra-ui/cli snippet add provider`
'use client'
import { ChakraProvider } from '@chakra-ui/react'
import { system } from '@/theme'
export function Provider(props: { children: React.ReactNode }) {
return <ChakraProvider value={system}>{props.children}</ChakraProvider>
}And the root layout, for a Next.js App Router build:
// src/app/layout.tsx
import { Provider } from '@/components/ui/provider'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<Provider>{children}</Provider>
</body>
</html>
)
}The lang="en" attribute is not cosmetic; screen readers use it to pick the right pronunciation rules. Most generic Chakra tutorials skip this and ship a product that announces "1965" as "one nine six five" to a NVDA user. For an edu product, that is a regression you cannot ship.
Accessibility-first patterns: Section 508, WCAG 2.1 AA, IDEA Act
This is the section the SERP does not write. Two things have to be true at the same time: Chakra's components are accessibility-aware out of the box, and your product is not Section 508 conformant just because you installed Chakra. The first is a property of the component library; the second is a property of the entire product. Naming the line is the difference between a builder who passes a procurement review and a builder who finds out at the last minute the district will not buy.
What Chakra gets right by default:
<Button>has the right role and is keyboard-focusable. The disabled state announces correctly. The loading state announces "loading" to screen readers.<Dialog>(modal) traps focus inside the modal, returns focus to the trigger on close, and announces with the right ARIA labels.<Tabs>supports arrow-key navigation, announces the selected tab, and the panel has the rightaria-labelledbylinkage.<Menu>supports keyboard navigation, types-to-search, and screen-reader announcement of the menu state.<Alert>withstatus="error"usesrole="alert", which screen readers announce immediately.- Form controls (
<Input>,<Select>,<Checkbox>,<Radio>) wire to labels viaFormControland announce error messages viaaria-describedby. focus-visibleis on by default, so a keyboard user sees the focus ring and a mouse user does not, without you writing a single CSS rule.- Color tokens can be checked at AA contrast using axe-core during development; Chakra does not auto-check, but the design tokens are exposed in a way that a contrast linter can read.
What is still on the builder:
- Semantic page structure. A page that uses
<div>for everything is not accessible even with Chakra. Use<header>,<main>,<nav>,<footer>,<section>, and a single<h1>per page. Chakra ships these asHeading,Box, and so on, but the choice of which to use is yours. - Color contrast for custom tokens. Chakra's default palettes are conservative. If you override a brand color, run an axe-core contrast check before shipping.
- Alt text on every image.
<Image alt="..." />is your job. A decorative image takesalt="". A meaningful image takes a description. A screen-reader user reads this aloud. - Captions on every video. WCAG 2.1 AA requires captions on pre-recorded audio. Chakra does not produce captions. YouTube auto-captions are not enough for a Section 508 audit; you need accurate captions, written or reviewed by a human.
- Keyboard testing. Tab through your whole product without a mouse. Every interactive control should be reachable, every action should be performable, and every modal should be escapable.
- Screen-reader testing. Use NVDA on Windows, VoiceOver on macOS / iOS, TalkBack on Android. Run through your three audience flows (student, teacher, parent) with each one.
- Captioned audio and transcripts. If your quiz reads a passage aloud, the transcript and captions are your work, not the library's.
- The VPAT itself. A Voluntary Product Accessibility Template is a sworn statement; the company or the individual builder fills it in based on what the product actually does, not on what the library claims. Most districts accept the WCAG 2.1 AA conformance report template.
To be explicit and to never misrepresent: Chakra UI is a component library; it is not a regulated entity, it does not certify Section 508 conformance, and no component library can make your product Section 508 conformant on its own. The statement "Chakra UI is Section 508 compliant" is a category error. The defensible statement is "Chakra UI ships components that, when used correctly inside a product that handles content semantically and audits the rest of its surface, can meet Section 508 and WCAG 2.1 AA conformance criteria." That is the line every teacher-builder should be able to say out loud to a district IT lead without flinching.
The IDEA Act (Individuals with Disabilities Education Act) is a related but distinct frame. IDEA requires public schools to provide accessible educational materials to students with disabilities. The "Accessible Educational Materials" (AEM) requirement covers the materials themselves: a textbook, an assignment, a quiz prompt. The software that delivers those materials has to render AEM correctly; that is on the builder. If your product delivers a math worksheet to a student with low vision, the math worksheet has to be screen-reader-navigable, not just visually visible. Chakra components can render the worksheet; the worksheet's own structure (headings, math markup, alt text on diagrams) is the AEM work.
For a deeper accessibility pattern reference inside the Solomon Signal canon, the Material UI for healthcare app builders page documents the same compliance-vs-library distinction in the HIPAA / WCAG context. The two pages are deliberately complementary; both teach the same lesson about what a component library can and cannot do, with two different domain constraints layered on top.
Kid-friendly UI patterns: tap targets, contrast, fonts, low-jargon labels
Kid-friendly is not a vibe; it is a measurable set of design decisions. A first-grader has different motor control than a sixth-grader, who has different motor control than a high-school junior. WCAG 2.1 AA defines a 44 × 44 CSS-pixel minimum tap target for AAA; you should ship to AAA for elementary. Chakra makes that explicit at the prop level.
The size scale, by grade band:
// src/components/AgeAwareButton.tsx
import { Button, ButtonProps } from '@chakra-ui/react'
type Band = 'elementary' | 'middle' | 'high' | 'parent'
// Each band's height in px maps to WCAG / parent-readability evidence:
// elementary: 56px (AAA, big-finger friendly)
// middle: 48px (AA+, still chunky)
// high / parent: 44px (AA minimum)
const heights: Record<Band, string> = {
elementary: '56px',
middle: '48px',
high: '44px',
parent: '44px',
}
const fontSizes: Record<Band, string> = {
elementary: '20px', // ~14pt, comfortable for early readers
middle: '18px',
high: '16px',
parent: '18px', // adults reading at arm's length on a phone
}
export function AgeAwareButton({ band, children, ...rest }: ButtonProps & { band: Band }) {
return (
<Button
h={heights[band]}
px="6"
fontSize={fontSizes[band]}
fontWeight="600"
colorPalette={band === 'elementary' ? 'purple' : 'blue'}
{...rest}
>
{children}
</Button>
)
}Contrast and color, by grade band:
- Elementary (K-2, ages 5-8). High-saturation primaries on white. Avoid pastels; pastels fail AA at low font sizes. The Chakra
purple.600onwhitetoken pair is the safe default in the kid theme. - Middle (3-8, ages 9-13). Less saturated, more grown-up. Slightly tighter buttons. The brand blue still works.
- High school (9-12, ages 14-18). Treat the student as an adult. Use the same theme tokens as the parent / teacher views. Add a dark mode toggle.
Font scaling, with a single fontSize token map:
// src/components/EduText.tsx
import { Text, TextProps } from '@chakra-ui/react'type Band = 'elementary' | 'middle' | 'high' | 'parent'
const sizes: Record<Band, string> = { elementary: 'xl', // ~20px in default Chakra scale middle: 'lg', // ~18px high: 'md', // ~16px parent: 'lg', // ~18px, for readability at arm's length }
export function EduText({ band, children, ...rest }: TextProps & { band: Band }) { return ( <Text fontSize={sizes[band]} lineHeight="1.6" {...rest}> {children} </Text> ) }
Low-jargon labels are a writing job, not a code job, and they are the single biggest accessibility win in an elementary app. A button labelled "Submit" makes sense to an adult and is confusing to a 6-year-old. The same button labelled "Send my answer" is clearer. The Chakra `<Button>` is the same component either way; the label is on you. Run every button label past a child of the target age before you ship.
A quick working example: the elementary practice card.
```tsx
// src/components/PracticeCard.tsx — an elementary-style flashcard
import { Box, Card, Heading, Stack, Image } from '@chakra-ui/react'
import { AgeAwareButton } from './AgeAwareButton'
import { EduText } from './EduText'
export function PracticeCard({ word, image, onKnow, onSkip }: {
word: string
image: string
onKnow: () => void
onSkip: () => void
}) {
return (
<Card.Root p="6" borderRadius="2xl" maxW="md" mx="auto">
<Stack gap="4" align="center">
<Image src={image} alt={`Picture of a ${word}`} boxSize="160px" />
<Heading size="2xl">{word}</Heading>
<EduText band="elementary">Do you know this word?</EduText>
<Stack direction="row" gap="3">
<AgeAwareButton band="elementary" onClick={onKnow} aria-label="I know this word">
I know it
</AgeAwareButton>
<AgeAwareButton band="elementary" onClick={onSkip} variant="outline" aria-label="Skip this word for now">
Skip
</AgeAwareButton>
</Stack>
</Stack>
</Card.Root>
)
}Note the explicit aria-label on each button. The visible text "I know it" is short and friendly for a child; the screen-reader label "I know this word" is descriptive for an assistive-tech user. Both audiences win.
Parent-portal UI patterns: low-jargon, high-contrast, screen-reader-ready forms
The parent portal is the most accessibility-fragile surface in an edu product. A parent reading a report card at 9 pm on a phone in low light, possibly with reading glasses, possibly with a screen reader, is the persona that breaks most generic React UIs. The pattern set:
- Body text at 18 px, line-height 1.6. No smaller. Chakra
TextwithfontSize="lg"andlineHeight="1.6"is the working default. - A high-contrast palette in light mode and a true dark mode for night reading. Tokens defined in both modes; never a single-mode-only color.
- Forms with explicit labels, never placeholder-as-label. Placeholders disappear when a parent starts typing; the label has to stay visible.
- Error messages associated to the field via
aria-describedby. Chakra'sField(v3) wires this for you when you useField.ErrorText. - Buttons labelled in parent-language. "Email the teacher" not "Submit."
- Avoid horizontal scrolling at any viewport. Test at 320 px wide.
A working parent-portal message form:
// src/components/ParentMessageForm.tsx
import { Box, Button, Field, Input, Stack, Textarea, Heading } from '@chakra-ui/react'
import { useState } from 'react'
export function ParentMessageForm({ onSend }: { onSend: (msg: { subject: string; body: string }) => Promise<void> }) {
const [subject, setSubject] = useState('')
const [body, setBody] = useState('')
const [error, setError] = useState<string | null>(null)
async function handleSubmit(e: React.FormEvent) {
e.preventDefault()
if (subject.length < 3) return setError('Please write a short subject so the teacher knows what your message is about.')
if (body.length < 10) return setError('Please write a few words so the teacher can help.')
setError(null)
await onSend({ subject, body })
}
return (
<Box as="form" onSubmit={handleSubmit} maxW="lg" mx="auto" p="6">
<Stack gap="4">
<Heading size="lg">Email the teacher</Heading>
<Field.Root invalid={!!error && subject.length < 3}>
<Field.Label fontSize="lg">What is your message about?</Field.Label>
<Input
value={subject}
onChange={(e) => setSubject(e.target.value)}
placeholder="Math homework on Wednesday"
fontSize="lg"
size="lg"
/>
</Field.Root>
<Field.Root invalid={!!error && body.length < 10}>
<Field.Label fontSize="lg">Your message</Field.Label>
<Textarea
value={body}
onChange={(e) => setBody(e.target.value)}
placeholder="Tell the teacher what is going on…"
fontSize="lg"
minH="32"
/>
{error && <Field.ErrorText>{error}</Field.ErrorText>}
</Field.Root>
<Button type="submit" colorPalette="blue" size="lg" alignSelf="flex-start">
Send to the teacher
</Button>
</Stack>
</Box>
)
}The label text is everyday English: "What is your message about?" instead of "Subject." "Your message" instead of "Body." "Send to the teacher" instead of "Submit." A parent who speaks English as a second language, or who is reading on a phone at 9 pm, parses this without effort. A screen reader announces "What is your message about? Edit, blank": clean, complete, conversational. That is the bar for a parent portal.
Classroom-tracking patterns: roster grid, gradebook table, assignment grading
A teacher's daily workflow is roster-shaped. The product the teacher builds will be roster-shaped too. Chakra's Table (v3) gives you everything except the data layer. Here is the working roster pattern.
// src/components/RosterTable.tsx
import { Table, Badge, Heading, Stack } from '@chakra-ui/react'
type Student = {
id: string
firstName: string
lastName: string
grade: number
recentScore: number
attendance: 'present' | 'absent' | 'late'
}
export function RosterTable({ students }: { students: Student[] }) {
return (
<Stack gap="3">
<Heading size="md">Period 3 — Algebra I</Heading>
<Table.ScrollArea>
<Table.Root size="sm" stickyHeader striped="even">
<Table.Header>
<Table.Row>
<Table.ColumnHeader>Last name</Table.ColumnHeader>
<Table.ColumnHeader>First name</Table.ColumnHeader>
<Table.ColumnHeader>Recent score</Table.ColumnHeader>
<Table.ColumnHeader>Attendance</Table.ColumnHeader>
</Table.Row>
</Table.Header>
<Table.Body>
{students.map((s) => (
<Table.Row key={s.id}>
<Table.Cell fontWeight="600">{s.lastName}</Table.Cell>
<Table.Cell>{s.firstName}</Table.Cell>
<Table.Cell>{s.recentScore}%</Table.Cell>
<Table.Cell>
<Badge colorPalette={s.attendance === 'present' ? 'green' : s.attendance === 'late' ? 'yellow' : 'red'}>
{s.attendance}
</Badge>
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table.Root>
</Table.ScrollArea>
</Stack>
)
}size="sm" and stickyHeader are the two density wins. A homeroom teacher with 32 students per period across 6 periods can see her whole roster without scrolling-fatigue. The Badge component announces the attendance state correctly to a screen reader because it ships with aria-label semantics. Sort and filter live one layer up (a controlled state hook or a TanStack Table integration); Chakra does not own the data layer and should not be asked to.
Assignment grading, then. A simple per-student score input with keyboard-first interaction:
// src/components/GradeRow.tsx
import { Input, HStack, Text } from '@chakra-ui/react'
import { useState } from 'react'
export function GradeRow({ studentName, max, onScore }: {
studentName: string
max: number
onScore: (n: number) => void
}) {
const [val, setVal] = useState('')
return (
<HStack gap="3" p="2" borderBottomWidth="1px" w="full">
<Text w="48" truncate>{studentName}</Text>
<Input
type="number"
min={0}
max={max}
value={val}
onChange={(e) => setVal(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
const n = Number(val)
if (!Number.isNaN(n) && n >= 0 && n <= max) onScore(n)
}
}}
aria-label={`Score for ${studentName} out of ${max}`}
size="sm"
w="20"
/>
<Text color="fg.muted">/ {max}</Text>
</HStack>
)
}Enter-to-save means a teacher grading 60 assignments at the end of the day never has to take her hand off the keyboard. The aria-label says "Score for Jordan Cruz out of 25" to a screen reader; the visible UI says "/ 25" because that is what the teacher's eye is scanning for.
Quiz and assessment patterns: timer, locked state, immediate feedback
The quiz is the highest-stakes screen in an edu app. A leaked answer, a timer that does not honor pause, an immediate-feedback reveal that announces too much to a screen reader: any of these is a story the next day. Chakra gives you the primitives; the discipline is yours.
A locked-state quiz tab pattern. The student cannot see the questions until "Begin" is clicked, and the timer starts only on click:
// src/components/QuizGate.tsx
import { Button, Tabs, Alert, Heading, Stack, Text } from '@chakra-ui/react'
import { useState, useEffect } from 'react'
export function QuizGate({ durationSec, questions, onSubmit }: {
durationSec: number
questions: { id: string; prompt: string; choices: string[] }[]
onSubmit: (answers: Record<string, number>) => void
}) {
const [started, setStarted] = useState(false)
const [remaining, setRemaining] = useState(durationSec)
const [answers, setAnswers] = useState<Record<string, number>>({})
useEffect(() => {
if (!started) return
const t = setInterval(() => setRemaining((r) => r - 1), 1000)
return () => clearInterval(t)
}, [started])
useEffect(() => {
if (remaining <= 0 && started) onSubmit(answers)
}, [remaining, started, answers, onSubmit])
if (!started) {
return (
<Stack gap="4" align="center" p="8">
<Heading size="lg">Algebra I — Chapter 3 Check</Heading>
<Text>You will have {Math.round(durationSec / 60)} minutes once you begin.</Text>
<Button size="lg" colorPalette="green" onClick={() => setStarted(true)}>
Begin
</Button>
</Stack>
)
}
return (
<Stack gap="4">
<Alert.Root status={remaining < 30 ? 'warning' : 'info'} aria-live="polite">
<Alert.Indicator />
<Alert.Title>Time remaining: {Math.max(0, remaining)} seconds</Alert.Title>
</Alert.Root>
<Tabs.Root defaultValue={questions[0].id}>
<Tabs.List>
{questions.map((q, i) => (
<Tabs.Trigger key={q.id} value={q.id}>Q{i + 1}</Tabs.Trigger>
))}
</Tabs.List>
{questions.map((q) => (
<Tabs.Content key={q.id} value={q.id}>
<Heading size="md">{q.prompt}</Heading>
<Stack mt="3">
{q.choices.map((c, i) => (
<Button
key={i}
variant={answers[q.id] === i ? 'solid' : 'outline'}
onClick={() => setAnswers((a) => ({ ...a, [q.id]: i }))}
size="lg"
textAlign="left"
justifyContent="flex-start"
>
{c}
</Button>
))}
</Stack>
</Tabs.Content>
))}
</Tabs.Root>
<Button colorPalette="blue" size="lg" onClick={() => onSubmit(answers)}>
Submit answers
</Button>
</Stack>
)
}Three things to notice. First, the questions are not rendered until started is true, so a curious student cannot peek at them via dev tools before clicking Begin. (A determined student can still inspect the network payload; this is a UX gate, not a security boundary. If your test is high-stakes, the server should serve the questions only after the student clicks Begin.) Second, the timer Alert uses aria-live="polite" so the time announcement does not interrupt a screen reader mid-question. Third, the choice Buttons use justifyContent="flex-start" so the answer text reads left-aligned the way a student expects, a small detail that matters a lot in practice.
Immediate-feedback reveal, for a practice mode (not a high-stakes test):
// src/components/AnswerReveal.tsx
import { Collapsible, Box, Text, Button } from '@chakra-ui/react'
import { useState } from 'react'export function AnswerReveal({ correctAnswer, explanation }: { correctAnswer: string; explanation: string }) { const [open, setOpen] = useState(false) return ( <Box mt="2"> <Button size="sm" variant="ghost" onClick={() => setOpen((o) => !o)} aria-expanded={open}> {open ? 'Hide answer' : 'Show answer'} </Button> <Collapsible.Root open={open}> <Collapsible.Content> <Box mt="2" p="3" bg="green.subtle" borderRadius="md"> <Text fontWeight="600">Answer: {correctAnswer}</Text> <Text mt="1">{explanation}</Text> </Box> </Collapsible.Content> </Collapsible.Root> </Box> ) }
`Collapsible` ships with the right `aria-expanded` state and the screen reader announces "Show answer, collapsed" or "Hide answer, expanded" depending on state. A practice-mode student gets the right level of feedback; a high-stakes test does not use this component at all.
## Handoff to a school IT team: documentation and a pre-submission accessibility audit
The product is built. The district IT lead wants the keys. The handoff is what determines whether the product gets adopted. Three deliverables, in order of how much a district wants to see them.
**1. A README that explains what the product does, who runs it, and how to evaluate it.** Half a page. The audience is a school IT director, not a fellow developer. Include the product's three audiences, the authentication model, the data the product stores, and the contact for accessibility questions.
**2. A VPAT-style accessibility conformance report.** The Information Technology Industry Council publishes a VPAT 2.5 template; the WCAG 2.1 AA conformance template is what most school districts will accept. Fill it out honestly: where the product supports a criterion, write "Supports"; where it partially supports, write "Partially supports" and explain; where it does not, write "Does not support" and explain the mitigation. A district will respect a honest "partially supports" entry more than an aspirational "supports" they will catch later.
**3. A pre-submission manual audit checklist.** A 30-minute pass before you hand the URL over:
* Open the home, login, primary student view, primary teacher view, and parent view. Tab through each one with a mouse-free keyboard. Every interactive control must be reachable, every action performable, every modal escapable with Escape.
* Run axe DevTools (Chrome extension) on each page. Resolve every Critical and Serious finding. Document any Moderate findings you accept and why.
* Run Lighthouse on each page (Performance + Accessibility + Best Practices + SEO). Aim for ≥95 Accessibility. Document any score under 95.
* Test with NVDA on Windows on the student and parent views. Confirm the main flows announce correctly. The first 60 seconds is the most important.
* Confirm captions are present and accurate on every video the product shows. YouTube auto-captions are not accurate enough; review every line.
* Confirm color contrast on every brand-color button against its background passes AA (4.5:1 for body text, 3:1 for large text). Use the WebAIM contrast checker.
* Confirm every image has an `alt` attribute (decorative images get `alt=""`; meaningful images get a description).
* Confirm the product is usable at 200% browser zoom without horizontal scrolling.
* Confirm reduced motion is respected (the product does not autoplay animations if the OS reports `prefers-reduced-motion: reduce`).
The handoff is also a chance to cross-link the rest of the Chakra reading list a school IT team or a follow-on developer might need. The [Chakra UI tool page](/launch-school/tools/chakra-ui) collects the working knowledge in one place; [Chakra UI best practices](/launch-school/tutorials/chakra-ui-best-practices) is the maintenance reference; the [Chakra UI alternatives page](/launch-school/alternatives/chakra-ui) names the other libraries a district might already have in its catalog. For builders shipping past the education space and into a content-creator-style product later, the [Chakra UI for content creators](/launch-school/use-cases/chakra-ui-for-content-creators) page is the persona-sibling that maps the same component library onto a different audience.
## Frequently asked questions
**Is Chakra UI Section 508 compliant?**
Not as a stand-alone statement. Section 508 conformance is a property of a finished product, not a component library. Chakra UI ships components that are accessibility-aware (WAI-ARIA defaults, semantic HTML, keyboard navigation, focus management) and that can meet Section 508 / WCAG 2.1 AA criteria when used correctly inside a product that audits its content, structure, color contrast, captions, and keyboard flows end-to-end. A builder claiming "Section 508 compliant" on a VPAT is claiming it about the whole product. The component library is one ingredient.
**Is Chakra UI free for a school-district product?**
Yes. Chakra UI is licensed under the MIT License. Commercial use, modification, and redistribution are all allowed. A district can deploy a product built on Chakra UI without per-seat or per-school fees. The MIT license is the same model used by React, Next.js, and most of the modern JavaScript ecosystem.
**Chakra UI vs MUI for edu software: which one should I pick?**
For most teacher-builders, Chakra wins on theming ergonomics, accessibility-by-default, and the absence of paid-tier surprises. MUI wins if your product needs the DataGrid Pro tier (server-side rows for ≥10,000-row student data warehouses) or if your district already standardized on Material Design. Both ship WCAG 2.1 AA-aware components. The [Chakra UI alternatives page](/launch-school/alternatives/chakra-ui) compares the full set; the [Material UI for healthcare app builders](/launch-school/use-cases/material-ui-for-healthcare-workers) page documents the MUI compliance pattern if you want to compare directly.
**What is the best Chakra accessibility-audit pattern before submitting to a district?**
The 30-minute manual audit in the handoff section above: axe DevTools + Lighthouse + a screen-reader pass on each of the three audience views + a keyboard-only walk-through + WebAIM contrast checks on every brand color. Document the result as a VPAT 2.5 / WCAG 2.1 AA conformance report. Districts respect an honest "partially supports" entry with a documented mitigation more than an unsupported "supports."
**Can I use Chakra UI dark mode for a night-study app for older students?**
Yes. Chakra v3 ships a built-in `ColorMode` system; you wrap the app in the Provider, define both `base` and `_dark` token values, and toggle with `useColorMode`. For SSR-correct first paint (no flash of unstyled content), add `ColorModeScript` to the root layout. Both modes have to pass WCAG 2.1 AA contrast independently; the dark mode is not a free pass on contrast.
**What edu-specific UI patterns ship with Chakra by default?**
None ship as edu-specific components; Chakra is a general-purpose library. The edu-specific patterns are compositions you write on top of Chakra primitives. This page documents seven of them as copy-paste code: an age-aware Button, an audience-aware Text, an elementary practice card, a parent-portal message form, a roster table, a quiz with a locked-state gate, and an answer-reveal Collapsible. Those compositions, plus the three-audience `extendTheme`, are the working starter kit.
**Will Chakra UI bloat the bundle for a phone-on-3G classroom?**
Chakra v3's Panda CSS engine produces a smaller runtime than v2's Emotion engine; the difference is on the order of 30-40 KB gzipped. For a student or parent on a budget Android device on a slow connection, that matters. The mitigation is the same as for any React app: code-split per route, use dynamic imports for non-critical components (the analytics dashboard, the seldom-used admin panel), and audit the production bundle with `next build` or `vite build --report`. A working edu product on Chakra v3 ships at well under 200 KB gzipped on the first paint.
For the broader Chakra reference set, see the [Chakra UI tool page](/launch-school/tools/chakra-ui) for the working tool overview, the [Chakra UI best practices guide](/launch-school/tutorials/chakra-ui-best-practices) for the maintenance reference, the [Chakra UI alternatives page](/launch-school/alternatives/chakra-ui) for the other libraries a district might already have in its catalog, the [Chakra UI for content creators page](/launch-school/use-cases/chakra-ui-for-content-creators) for the persona-sibling that maps the same library onto a different audience, and the [Material UI for healthcare app builders page](/launch-school/use-cases/material-ui-for-healthcare-workers) for the parallel compliance-driven persona use-case. For authority references, the [Chakra UI official documentation](https://chakra-ui.com) is the source of truth on the live API and the [W3C WCAG 2.1 guidelines](https://www.w3.org/WAI/standards-guidelines/wcag/) are the source of truth on the conformance criteria a school district will ask about.
Build the gradebook. Ship it before September. The first student who uses it will not know what Chakra is and that is exactly the point.