Skip to content

KarlHorning.dev - Building a Modern, Accessible Developer Portfolio

| 6 min read

A TypeScript-based Next.js portfolio focused on accessibility, performance, and clean documentation.

Screenshot of Karl Horning's portfolio homepage

Overview

KarlHorning.dev is my centralised developer portfolio — a single, accessible Next.js build that replaces the need to maintain separate stacks. It brings together my projects, writing, and CMALT portfolio in one modular codebase, built with the same care I apply in a production environment.

It's a custom-built portfolio and blog designed to showcase my work as a Full-Stack JavaScript/TypeScript Developer and Learning Technologist. The site prioritises accessibility, performance, and maintainability, supported by consistent documentation and strong TypeScript typing.

I rebuilt the site while preparing my CMALT portfolio. I wanted something easier to read, more maintainable, and reflective of both my technical and educational background. My previous site lacked a dedicated Projects section, and this rebuild gave me the opportunity to include one — alongside a full blog and case study framework.

Tech Stack

  • Framework: Next.js 15 (App Router)
  • Language: TypeScript (strict mode)
  • UI: React 19 + Tailwind CSS
  • Tooling: ESLint + Prettier (Tailwind plugin)
  • Icons: React Icons
  • Image Optimisation: Sharp
  • Testing: Playwright + axe-core for end-to-end accessibility
  • Deployment: GitHub Pages (static export)
  • Accessibility: WCAG-aware design, semantic HTML, ARIA-friendly components

CI/CD: GitHub Actions runs type checks, linting, build, Playwright accessibility tests, and next export on push to main, then deploys automatically to GitHub Pages. Workflows include a composite Node setup/cache action and a Pages deployment pipeline.

Key Skills Demonstrated

  • Front-end architecture: Next.js 15, React 19, TypeScript
  • Styling and accessibility: Tailwind CSS, WCAG 2.2 AA, semantic HTML, ARIA
  • Performance and accessibility testing: Playwright + axe-core, Lighthouse, and static export
  • Documentation and consistency: TypeScript + JSDoc, predictable structure
  • Maintainability and quality: ESLint, Prettier, CI/CD automation
  • Deployment and scalability: GitHub Pages static deployment, JSON-based data

Design Approach

The design focuses on clarity, accessibility, and tone rather than visual noise. Typography and spacing follow a grid-based rhythm, with a restrained colour palette supporting both light and dark modes.

Animations are minimal — for example, the logo includes a subtle CSS glitch hover effect to add personality without distraction. All layouts are mobile-first and responsive, optimised for readability across devices.

Page Structure

The site is divided into structured, component-driven sections for easy maintenance and future scalability.

Home

A focused introduction with clear navigation and recent projects.

About

  • Values Grid: Highlights inclusive design, calm collaboration, and developer experience.
  • Technology Stack: Displays key technologies with consistent iconography.
  • Certifications: CELTA, PTLLS, Apple Teacher, Scrum Fundamentals.
  • Experience Timeline: Roles at Imperial College London and freelance work.

Projects & Case Studies

Showcases case studies with technologies and links. Each card is dynamically generated from JSON typed with ProjectMeta.

For example, see my detailed backend case study: Learnlight Platform & Mobile Apps.

CMALT Portfolio

A structured portfolio following the CMALT framework, linking to evidence documents, media, and reflections.

Contact

A minimal, accessible contact page with form, social links, and JSON-LD structured data for SEO.

Accessibility affordances are baked into the layout: a visible “Skip to content” link, and the main content wrapped in <main id=“main”> for keyboard and assistive tech users.

Architecture and Data Model

The codebase follows a clear separation of concerns between content, types, and logic.

  • Constants under lib/constants/ (assets, links, SEO, icons)
  • Shared types in src/types/ui.ts
  • Concise JSDoc annotations ensure every dataset is self-documented.

This structure makes the site predictable, modular, and easy to extend.

Content Architecture

A content-first approach stores data in JSON and TypeScript constants, making it portable and predictable.

  • Blog posts in public/data/posts.json typed with BlogPost.
  • Dynamic tag and search generation.
  • Projects follow the same structure for reusability.

By centralising content, I maintain static generation for GitHub Pages and eliminate the need for a separate Eleventy site.

Migrating from Eleventy to Next.js

I migrated from Eleventy (11ty) to Next.js to simplify the stack and unify my blog and portfolio under React components. The site remains fully static thanks to a JSON-based data layer and next export.

Documentation and Consistency

Each file includes JSDoc annotations describing its purpose and data structure, complementing TypeScript's static analysis.

/**
 * Centralised collection of external URLs used across the site.
 */
export const externalLinks: SiteLink = {
  GitHubLink: "https://github.com/Karl-Horning",
  PortfolioLink: "https://www.karlhorning.dev",
};

Accessibility and Performance

Accessibility is monitored throughout development and on the live site using Lighthouse, WAVE, and Firefox's built-in accessibility tools. The current live score is 100, and a full Lighthouse and accessibility audit is published from the production build.

  • Keyboard-friendly navigation
  • Proper alt text and ARIA attributes
  • High contrast in both light and dark modes
  • Static generation for speed and SEO
  • Optimised media via Next/Image and Sharp

Lighthouse Performance (Live): Mobile

Performance

97

Accessibility

100

Best Practices

100

SEO

100

Lighthouse report (mobile) run on 16 Oct 2025 against the live site.

Lighthouse Performance (Live): Desktop

Performance

99

Accessibility

100

Best Practices

100

SEO

100

These figures reflect the production environment as of 16 Oct 2025.

In addition to manual and Lighthouse testing, a full-site automated accessibility suite runs with Playwright and axe-core. Each route is rendered in a real browser and scanned against WCAG 2.2 AA criteria, ensuring zero accessibility violations before deployment. Current results: all pages pass with no detected issues.

Privacy, Security & Performance

The site is statically generated for reliability and security, with no user tracking or unnecessary third-party scripts. Assets are optimised using Sharp, and privacy-friendly analytics will be added to measure engagement responsibly.

Scalability and Future Development

The site's modular structure makes it easy to extend with new projects or features. Upcoming work includes adding Jest tests for interactive elements and exploring lightweight analytics for performance insights.

Development currently happens in refresh/2025-design, with feature and bug branches merged into that branch before PRs to main, which serves the live site.

Outcome

The finished site is a fast, accessible, and maintainable portfolio that represents both my technical and educational background. It consolidates my online presence, streamlines maintenance, and provides a flexible structure for showcasing projects.

It demonstrates proficiency in modern front-end development, an understanding of accessibility and inclusive design, and a commitment to clean, maintainable code. Ultimately, it reflects my core values: clarity, maintainability, and accessibility.

Consolidating 11ty into a single Next.js codebase reduces maintenance by roughly 2-3 hours per month, while keeping accessibility work and documentation in one place.

Why It Matters

I approach my personal site as I do a client project — with attention to accessibility, structure, and maintainability. Building it this way keeps my skills sharp and demonstrates the standards I apply in professional environments, without unnecessary complexity. It also serves as a living example of my front-end principles in practice.

Further Reading

Share:PostShare

Want a deeper dive?

I can share private repos, extended write-ups and implementation notes on request.