# Academy Page

> A learning academy page: a drawn course player, progress and streaks, learning paths, a filterable course catalog and certifications.

- Type: React template (Templates)
- Access: Pro (the source needs a Wingo UI Pro plan, see https://wingo-ui.com/pricing)
- Version: 1.0.0
- Install: `npx wingo-ui@latest add academy-page`
- Docs: https://wingo-ui.com/templates/academy-page

## Interaction

The hero rises in once on mount beside a drawn course player (a lesson poster with a play button and scrubber, the chapter list with checkmarks) that settles into place over a soft glow, with a streak chip, a passed quiz and a certificate floating around it on wide screens. Start learning jumps to the catalog, Browse learning paths to the paths. Continue learning greets a signed-in learner with the course in progress (a progress ring, the next lesson, Resume and Syllabus), a streak card with this week's days and the weekly XP goal, and a rail of other courses in progress (swipeable on phones); with learner set to null it shows a sign-in prompt instead. Each learning path draws its courses as nodes on a track (done, up next, not started) ending in a certificate badge; View courses filters the catalog to that path and scrolls there, with a removable path chip. The catalog searches titles, summaries, topics and instructors as you type, filters by topic (a chip row that scrolls sideways on phones) and level (a segmented control), sorts by popularity, date, rating or length, shows the first nine courses with Show all, and an empty state with Clear filters. Clicking a course opens its preview as a dialog (a bottom sheet below 768px): a drawn preview, stats, what you'll learn, the syllabus as an accordion of modules and lessons with durations, and the instructor. Enroll for free spins while onEnroll runs (900 ms without one), then shows You're enrolled, swaps the button for Start course and puts the course at the front of Continue learning. Certifications show drawn badges, requirements and exam facts; Verify a certificate checks the ID format, spins, then shows the certificate (valid or expired) or a not found message. Live sessions link to events; learner quotes, the FAQ and the footer newsletter follow. Reduced motion keeps everything still.

## Installation

```bash
npx wingo-ui@latest add academy-page
```

Pro item: run `npx wingo-ui@latest login` once with a Pro account. The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add @wingo-ui/academy-page` (needs the @wingo-ui registry with your API key in components.json)

Files:

- `components/templates/academy-page.tsx`
- `components/templates/academy-page-data.ts`

npm dependencies: `npm i lucide-react motion`

Wingo UI dependencies (installed automatically):

- [Marketing Section](https://wingo-ui.com/components/marketing-section) ([Markdown](https://wingo-ui.com/components/marketing-section.md))
- [Marketing Header](https://wingo-ui.com/components/marketing-header) ([Markdown](https://wingo-ui.com/components/marketing-header.md))
- [Marketing Footer](https://wingo-ui.com/components/marketing-footer) ([Markdown](https://wingo-ui.com/components/marketing-footer.md))
- [Testimonials Section](https://wingo-ui.com/components/testimonials-section) ([Markdown](https://wingo-ui.com/components/testimonials-section.md))
- [FAQ Section](https://wingo-ui.com/components/faq-section) ([Markdown](https://wingo-ui.com/components/faq-section.md))
- [CTA Section](https://wingo-ui.com/components/cta-section) ([Markdown](https://wingo-ui.com/components/cta-section.md))
- [Accordion](https://wingo-ui.com/components/accordion) ([Markdown](https://wingo-ui.com/components/accordion.md))
- [Avatar](https://wingo-ui.com/components/avatar) ([Markdown](https://wingo-ui.com/components/avatar.md))
- [Button](https://wingo-ui.com/components/button) ([Markdown](https://wingo-ui.com/components/button.md))
- [Dialog](https://wingo-ui.com/components/dialog) ([Markdown](https://wingo-ui.com/components/dialog.md))
- [Empty State](https://wingo-ui.com/components/empty-state) ([Markdown](https://wingo-ui.com/components/empty-state.md))
- [Input](https://wingo-ui.com/components/input) ([Markdown](https://wingo-ui.com/components/input.md))
- [Progress](https://wingo-ui.com/components/progress) ([Markdown](https://wingo-ui.com/components/progress.md))
- [Search Input](https://wingo-ui.com/components/search-input) ([Markdown](https://wingo-ui.com/components/search-input.md))
- [Segmented Control](https://wingo-ui.com/components/segmented-control) ([Markdown](https://wingo-ui.com/components/segmented-control.md))
- [Select](https://wingo-ui.com/components/select) ([Markdown](https://wingo-ui.com/components/select.md))
- [Motion presets](https://wingo-ui.com/components/motion) ([Markdown](https://wingo-ui.com/components/motion.md))
- [Navigation](https://wingo-ui.com/components/navigation) ([Markdown](https://wingo-ui.com/components/navigation.md))
- [Text match](https://wingo-ui.com/components/text-match) ([Markdown](https://wingo-ui.com/components/text-match.md))
- [Tones](https://wingo-ui.com/components/tones) ([Markdown](https://wingo-ui.com/components/tones.md))
- [UIProvider](https://wingo-ui.com/components/ui-config) ([Markdown](https://wingo-ui.com/components/ui-config.md))

## Usage

```tsx
// app/(marketing)/academy/page.tsx
"use client"

import Link from "next/link"
import { AcademyPage } from "@/components/templates/academy-page"

export default function AcademyRoute() {
  return (
    <AcademyPage
      linkComponent={Link}
      ctaTone="brand"
      onEnroll={async (course) => {
        const response = await fetch("/api/academy/enroll", { method: "POST", body: JSON.stringify({ courseId: course.id }) })
        if (!response.ok) throw new Error("Could not enroll")
      }}
      onVerify={async (id) => {
        const response = await fetch(`/api/academy/certificates/${id}`)
        return response.ok ? response.json() : null
      }}
    />
  )
}
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `design?` | `"classic" \| "bold" \| "minimal"` | `"classic"` | The whole page's look. classic follows the layout props: a split hero with the player on the right over a dotted glow; bold: a pill header, a giant stage title on a color mesh, rounder panels, an inverted Verify panel, a quote wall, FAQ cards, an image band and a wordmark footer; minimal: a transparent header, a centered stacked hero, no glow or floating chips, outlined flat panels, gray thumbnails, no bands and a simple footer. The *Props overrides still win. |
| `topics?` | `AcademyTopic[]` | `"ACADEMY_TOPICS"` | The topic chips, { value, label, icon? }; only topics that hold courses show. |
| `courses?` | `AcademyCourse[]` | `"ACADEMY_COURSES"` | The catalog: { id, title, summary, topic, level, scene (the drawn thumbnail), accent?, rating, ratings, learners, instructor, badge?, publishedAt, outcomes, modules: { id, title, lessons: { title, minutes, kind? }[] }[] }. |
| `paths?` | `AcademyPath[]` | `"ACADEMY_PATHS"` | Learning paths: { id, title, description, level, courseIds, certificationId?, icon?, accent? }; each course is a node on the drawn track. |
| `certifications?` | `AcademyCertification[]` | `"ACADEMY_CERTIFICATIONS"` | { id, name, level, description, requirements, exam: { questions, minutes, passScore, price }, holders, validMonths, shape, accent?, code }. |
| `issuedCertificates?` | `AcademyIssuedCertificate[]` | `"ACADEMY_ISSUED_CERTIFICATES"` | What the pretend Verify looks IDs up in when there is no onVerify. |
| `learner?` | `AcademyLearner \| null` | `"ACADEMY_LEARNER"` | The signed-in learner: { name, avatar?, courses: { courseId, completed }[], paths?, streak, week, today?, xp, weeklyXp, weeklyGoal }. null shows the signed-out page with a sign-in prompt. |
| `sessions?` | `AcademySession[]` | `"ACADEMY_SESSIONS"` | Live sessions: { id, kind, title, startsAt (ISO, UTC), minutes, host }. |
| `stats?` | `AcademyStat[]` | `"ACADEMY_STATS"` | The hero numbers: { value, label, decimals?, suffix? }. |
| `testimonials?` | `Testimonial[]` | `"ACADEMY_TESTIMONIALS"` | Learner quotes: { quote, name, role?, company?, companyIcon?, metric? }. |
| `faq?` | `FaqItem[]` | `"ACADEMY_FAQ"` | { question, answer } pairs about the Academy. |
| `labels?` | `Partial<AcademyPageLabels>` | `"DEFAULT_ACADEMY_PAGE_LABELS"` | Every visible string; the ones with numbers in them are functions. |
| `hrefs?` | `Partial<AcademyPageHrefs>` | `"DEFAULT_ACADEMY_PAGE_HREFS"` | { catalog, paths, course, signIn, signUp, events, examGuide }; a course's page is `${course}/${id}`. |
| `heroCourseId?` | `string` | `"automations-101"` | The course drawn in the hero's player. |
| `defaultTopic?` | `string` | `"all"` | The topic filter on load: all or a topic value. |
| `defaultLevel?` | `"all" \| "beginner" \| "intermediate" \| "advanced"` | `"all"` | The level filter on load. |
| `defaultSort?` | `"popular" \| "newest" \| "rating" \| "shortest"` | `"popular"` | The catalog's order on load. |
| `pageSize?` | `number` | `9` | Courses shown before Show all; 0 shows every course. |
| `thumbnails?` | `"color" \| "mono"` | `"color"` | Course thumbnails tinted with each course's accent, or all gray. Applies to the classic and bold designs. |
| `testimonialsLayout?` | `"featured" \| "grid" \| "carousel" \| "marquee"` | `"featured"` | Learner quotes as one big quote and two small, a masonry grid, a swipeable rail or drifting rows. Applies to the classic design. |
| `ctaVariant?` | `"inverted" \| "soft" \| "split"` | `"inverted"` | The closing band: a solid band, a gray band, or copy beside the buttons on a raised panel. Applies to the classic design. |
| `showAnnouncement?` | `boolean` | `true` | The strip above the header bar. |
| `showStats?` | `boolean` | `true` | The hero's numbers. |
| `showContinue?` | `boolean` | `true` | Continue learning, or the sign-in prompt when signed out. |
| `showPaths?` | `boolean` | `true` | The learning paths. |
| `showCatalog?` | `boolean` | `true` | The course catalog. |
| `showCertifications?` | `boolean` | `true` | The certification cards. |
| `showVerify?` | `boolean` | `true` | The Verify a certificate panel. |
| `showSessions?` | `boolean` | `true` | The live sessions. |
| `showTestimonials?` | `boolean` | `true` | The learner quotes. |
| `showFaq?` | `boolean` | `true` | The FAQ. |
| `showCta?` | `boolean` | `true` | The closing call to action. |
| `alternate?` | `boolean` | `true` | Gray bands on every other section. Applies to the classic and bold designs. |
| `tone?` | `"neutral" \| "brand" \| "success" \| "warning" \| "danger" \| "info"` | `"neutral"` | Accents across the page: the hero glow, progress rings and bars, streak days, path nodes, topic chips, the level control and checks. |
| `ctaTone?` | `"neutral" \| "brand" \| "success" \| "warning" \| "danger" \| "info"` | `"neutral"` | Start learning, Resume, Enroll for free, Verify, Sign in, the header's Get started and the closing band; brand is the marketing orange. |
| `header?` | `boolean` | `true` | The marketing header; off inside a site layout. |
| `footer?` | `boolean` | `true` | The marketing footer with its newsletter form. |
| `headerProps?` | `Partial<MarketingHeaderProps>` |  | Passed to MarketingHeader. |
| `footerProps?` | `Partial<MarketingFooterProps>` |  | Passed to MarketingFooter. |
| `testimonialsProps?` | `Partial<TestimonialsSectionProps>` |  | Overrides for the TestimonialsSection. |
| `faqProps?` | `Partial<FaqSectionProps>` |  | Overrides for the FaqSection. |
| `ctaProps?` | `Partial<CtaSectionProps>` |  | Overrides for the CtaSection. |
| `onEnroll?` | `(course: AcademyCourse) => (void \| Promise<unknown>)` |  | Enroll for free. A promise keeps the button loading and a rejection shows an error in the dialog. Without it the button waits 900 ms; then the course counts as enrolled and joins Continue learning. |
| `onVerify?` | `(id: string) => (AcademyVerifyResult \| Promise<AcademyVerifyResult>)` |  | Looks a certificate ID up (already upper-cased and checked against ACME-XXX-00000). Resolve with the certificate or null; a rejection shows an error. Without it: 900 ms, then issuedCertificates. |
| `onCourseOpen?` | `(course: AcademyCourse) => void` |  | A course's preview opened. |
| `onSubscribe?` | `(email: string) => (void \| Promise<unknown>)` |  | The footer newsletter; a rejected promise shows an error. |
| `animateIn?` | `boolean` | `true` | The hero rises in once, the player settles into place and the quotes drift; false keeps the page still (thumbnails). Reduced motion always does. |
| `locale?` | `string` | `"en-US"` | Intl locale for counts, ratings, prices and dates (dates in UTC). |
| `linkComponent?` | `(props: LinkComponentProps) => ReactNode` | `"<a>"` | The router link for every link on the page (next/link in an app). |
| `className?` | `string` |  | Classes for the root. |
| `classNames?` | `Partial<Record<AcademyPageSlot, string>>` |  | Classes for header, hero, title, player, stats, continue, paths, path, catalog, toolbar, course, detail, certifications, certification, verify, sessions, testimonials, faq, cta and footer. |

## Parts

### ACADEMY_PAGE_SAMPLE (constant)

All the sample content in one object: topics, courses, paths, certifications, issued certificates, learner, sessions, stats, testimonials and faq.

### ACADEMY_TOPICS (constant)

Eight topics, from Getting started to Integrations and API.

### ACADEMY_COURSES (constant)

Sixteen courses with drawn thumbnails, instructors, outcomes and full syllabi.

### ACADEMY_PATHS (constant)

Acme Foundations, Workflow Automation, Team Admin and Acme for Product Managers.

### ACADEMY_CERTIFICATIONS (constant)

Acme Certified Admin, Builder and Expert.

### ACADEMY_ISSUED_CERTIFICATES (constant)

Three issued certificates for the pretend lookup: ACME-ADM-24817, ACME-BLD-50392 and ACME-EXP-00731.

### ACADEMY_LEARNER (constant)

Chloe Martin: three courses in progress, a 12-day streak and 320 of 500 XP this week.

### ACADEMY_SESSIONS (constant)

Three live sessions in October 2026: office hours, an AMA and a workshop.

### ACADEMY_STATS (constant)

16 free courses, 180,000+ learners, 3 certifications, 4.8 average rating.

### ACADEMY_TESTIMONIALS (constant)

Six learner quotes.

### ACADEMY_FAQ (constant)

Six questions about price, accounts, renewals, retakes, teams and captions.

### findAcademyCertificate (function)

(id, issued = ACADEMY_ISSUED_CERTIFICATES) => the issued certificate with that ID (trimmed, any case) or null.

### DEFAULT_ACADEMY_PAGE_LABELS (constant)

The English strings.

### DEFAULT_ACADEMY_PAGE_HREFS (constant)

The default link targets.

### ACADEMY_PAGE_DESIGNS (constant)

The design names, classic first: ["classic", "bold", "minimal"].

### AcademyPageProps (type)

Props of AcademyPage.

### AcademyPageDesign (type)

"classic" | "bold" | "minimal".

### AcademyCourse (type)

One course with its syllabus.

### AcademyModule (type)

A module of a course: { id, title, lessons }.

### AcademyLesson (type)

A lesson: { title, minutes, kind? }.

### AcademyPath (type)

One learning path.

### AcademyCertification (type)

One certification with its exam.

### AcademyIssuedCertificate (type)

A certificate someone earned: { id, holder, certificationId, issuedAt, expiresAt }.

### AcademyVerifyResult (type)

What onVerify resolves with: AcademyIssuedCertificate | null.

### AcademyLearner (type)

The signed-in learner's progress, streak and XP.

### AcademySession (type)

One live session.

### AcademyPageLabels (type)

The strings labels can override.

### AcademyPageHrefs (type)

The link targets hrefs can override.

## Examples

- **Bold design**: design="bold": a giant stage title on a color mesh, rounder panels, an inverted Verify panel, a quote wall and a wordmark footer.
- **Minimal design**: design="minimal": a transparent header, a centered hero, gray thumbnails, outlined panels, no gray bands and a simple footer.
- **Signed out, in brand orange**: learner={null} with tone and ctaTone brand: Continue learning becomes a sign-in prompt; enroll in a course to see it appear there.
- **Advanced automation courses**: defaultTopic automations, defaultLevel advanced and the newest first, with the API course in the hero and a grid of quotes.
- **Enrollment down**: An onEnroll that rejects: open a course and enroll to see the error while the button stays ready to try again.

## See also

- [Help Center Page](https://wingo-ui.com/templates/help-center-page) ([Markdown](https://wingo-ui.com/templates/help-center-page.md))
- [Docs Home Page](https://wingo-ui.com/templates/docs-home-page) ([Markdown](https://wingo-ui.com/templates/docs-home-page.md))
- [Events Page](https://wingo-ui.com/templates/events-page) ([Markdown](https://wingo-ui.com/templates/events-page.md))
- [Progress](https://wingo-ui.com/components/progress) ([Markdown](https://wingo-ui.com/components/progress.md))
- [Accordion](https://wingo-ui.com/components/accordion) ([Markdown](https://wingo-ui.com/components/accordion.md))

---

Canonical: https://wingo-ui.com/templates/academy-page
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
