MOVE YOUR BUSINESS FORWARD START WITH A FREE WEBSITE AUDIT

MOVE YOURBUSINESSFORWARD

START WITH A FREE WEBSITE AUDIT

// full-stack web developer

Ιοαnnis Καperdαs

I design and build high-performance websites and web apps. From strategy to launch.

tools & software

design · development · delivery

  • React
  • TypeScript
  • Next.js
  • Node.js
  • Tailwind CSS
  • PostgreSQL
  • Supabase
  • GraphQL
  • Figma
  • Framer
  • Adobe Photoshop
  • Adobe InDesign
  • Git
  • GitHub
  • Vercel

selected work: My latest projects

A few recent projects: the problem, what I shipped, and what changed.

CafeScoop screenshot

Recurring office ordering · 2026

CafeScoop

result

A direct channel that helps neighborhood cafés turn nearby offices into repeat customers, while each office gets a fast link-to-order flow and the café gets one clear ticket instead of message chaos.

1 link → 1 café ticket

project details
problem
Neighborhood cafés lose repeat office business to fragmented phone and WhatsApp orders: the same details are collected every day, cutoffs are unclear, and staff must manually combine each person's choices into one order.
built
A bilingual recurring-order platform in Next.js 15, TypeScript and Supabase. One organizer creates the group and schedule, teammates join from a link without required signup, the live order locks automatically, and the café receives one aggregated ticket. Kitchen workflow, email notifications, revenue reporting and Sentry complete the operating loop.
  • Next.js 15
  • TypeScript
  • Supabase
  • Realtime
  • EL / EN
open project

code: Recent Code Initiatives

Patterns I reach for on real work. Each one solves a problem you'll recognise. Pick one to read it.

Modal.tsx

Modal dialogs that trap focus and restore it, without pulling in a UI library.

View on GitHub
// Problem: accessible modal dialogs that trap focus and restore it on close,
// without pulling in a whole UI library.
import { useEffect, useRef } from "react";

export function Modal({ open, onClose, title, children }: {
  open: boolean;
  onClose: () => void;
  title: string;
  children: React.ReactNode;
}) {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!open) return;
    const previouslyFocused = document.activeElement as HTMLElement | null;
    const focusables = ref.current!.querySelectorAll<HTMLElement>(
      'a[href], button:not([disabled]), input, [tabindex]:not([tabindex="-1"])',
    );
    focusables[0]?.focus();

    function onKeyDown(e: KeyboardEvent) {
      if (e.key === "Escape") return onClose();
      if (e.key !== "Tab" || focusables.length === 0) return;
      const first = focusables[0];
      const last = focusables[focusables.length - 1];
      // Wrap focus so Tab never escapes the dialog.
      if (e.shiftKey && document.activeElement === first) {
        e.preventDefault();
        last.focus();
      } else if (!e.shiftKey && document.activeElement === last) {
        e.preventDefault();
        first.focus();
      }
    }

    document.addEventListener("keydown", onKeyDown);
    return () => {
      document.removeEventListener("keydown", onKeyDown);
      previouslyFocused?.focus(); // restore focus to the trigger element
    };
  }, [open, onClose]);

  if (!open) return null;
  return (
    <div className="overlay" onClick={onClose}>
      <div
        ref={ref}
        role="dialog"
        aria-modal="true"
        aria-label={title}
        onClick={(e) => e.stopPropagation()}
      >
        {children}
      </div>
    </div>
  );
}

about: Full-stack execution

I'm Ioannis Kaperdas, a full-stack web developer with hands-on experience delivering websites and web applications across a range of projects. I hold an MSc in Business Information Technology Systems from the University of Strathclyde and an MSc in IT and Applications from the University of West Attica.

I care about the things that make software actually good: fast load times, accessible markup, typed and maintainable code, and clear communication along the way.

Tools are means to an end. I pick the right ones for the job and keep the codebase something the next person can live with.

what I do

  • Web apps & dashboards
  • /Marketing & landing sites
  • /Performance & SEO
  • /Design to code
based in
Athens, Greece · Remote worldwide
stack
TypeScript · React · Next.js
working with
Startups, agencies & founders

// toolkit

  • TypeScript
  • React
  • Next.js
  • Node.js
  • Tailwind CSS
  • PostgreSQL
  • REST & GraphQL
  • Figma → Code
  • Web Vitals
  • Vercel / CI

contact: Let's work together

Have something in mind, or just want to chat? Tell me about it and I'll reply within a day.

Securing your message...