<MT />
Back to Blog
Next.jsSEOAccessibilityLighthouseWeb PerformancePortfolio

From 85 to 100: How I Fixed My Portfolio's Lighthouse Score (And What I Learned)

T

Muhammad Tayyab

March 31, 2026·7 min read
Analytics dashboard showing website performance metrics and scores

I ran Lighthouse on my own portfolio and got a brutal 85 on Accessibility and no SEO infrastructure at all — no robots.txt, no sitemap, no structured data. Here is exactly how I fixed it, what each change does, and why it matters.

I have a confession: I spent months building a portfolio that looked great but was basically invisible to Google and a nightmare for screen readers. Then I ran Lighthouse on it.

The scores came back: Performance 85, Accessibility 85, Best Practices 100, SEO 97. That SEO score looked okay — until I dug into what was actually missing. No robots.txt. No sitemap. Zero structured data. Icon-only buttons with no labels. Headings jumping from h1 straight to h3. The kind of stuff that makes accessibility engineers quietly weep.

Here is everything I fixed, why each change matters, and what the final scores looked like.

The Audit: What Lighthouse Actually Found

Lighthouse is a free tool built into Chrome DevTools. It audits your site across five categories: Performance, Accessibility, Best Practices, SEO, and PWA. Each one has a score from 0 to 100, and each flagged issue comes with a clear explanation of what is wrong and why it matters.

The issues on my portfolio fell into four buckets:

1. Missing SEO infrastructure — no robots.txt, no sitemap.xml, no structured data (JSON-LD), weak keyword coverage.

2. Buttons without accessible names — icon-only buttons that screen readers announce as just "button" with no context about what they do.

3. Broken heading hierarchy — the page logo was wrapped in an h3 tag, and sections jumped from h1 straight to h3 with no h2 in between.

4. Contrast failures — small gray text on white backgrounds that looked fine visually but failed WCAG contrast ratios.

Fix 1: robots.txt and sitemap.xml — The Basics Google Needs

When I visited https://iamtayyab.com/robots.txt, I got a 404. Same with /sitemap.xml. This means Google has no crawl directives and no map of what pages exist. Blog posts could take weeks to get indexed instead of days — or never get discovered at all.

In Next.js App Router, fixing this is dead simple. Create src/app/robots.ts and src/app/sitemap.ts — Next.js generates the files automatically at build time. For the sitemap, I also pull all blog posts from Sanity so every post URL is included automatically whenever a new one is published.

// src/app/robots.ts
export default function robots() {
  return {
    rules: { userAgent: '*', allow: '/' },
    sitemap: 'https://www.iamtayyab.com/sitemap.xml',
  };
}

Fix 2: Structured Data (JSON-LD) — Tell Google Who You Are

Structured data is machine-readable JSON embedded in your page that tells Google exactly what it is looking at. Without it, Google has to guess. With it, you are eligible for rich results — knowledge panels, sitelinks, enhanced search appearances.

I added two schemas to the homepage: a Person schema (who I am, my job title, location, and social profiles) and a WebSite schema. For each blog post, I completed the BlogPosting schema with missing fields — url, mainEntityOfPage, publisher, ImageObject dimensions, keywords, and dateModified. All of these help Google understand and categorize the content correctly.

const personJsonLd = {
  '@context': 'https://schema.org',
  '@type': 'Person',
  name: 'Muhammad Tayyab',
  url: 'https://www.iamtayyab.com',
  jobTitle: 'Full Stack Developer',
  address: {
    '@type': 'PostalAddress',
    addressLocality: 'Peshawar',
    addressCountry: 'PK',
  },
  sameAs: [
    'https://github.com/meetayyab',
    'https://x.com/iamtayyabx',
    'https://www.linkedin.com/in/immtayyab',
  ],
};

Fix 3: The Logo Was an h3 Tag (Yes, Really)

This one was subtle but important. The site logo in the header was wrapped in a Typography component set to variant="h3". That means every single page started with an h3 in the DOM before any content headings. Screen readers and search engines read the heading outline sequentially — so this was corrupting the document structure of every page on the site.

The fix was one line: change it to a span. Logos are not headings. They are brand identifiers. They have no place in the document outline.

// Before — logo polluting heading structure
const Logo = () => (
  <Typography variant="h3">{'<MT />'}</Typography>
);

// After — semantically correct
const Logo = () => (
  <span className="text-2xl font-bold text-gray-900">
    {'<MT />'}
  </span>
);

Fix 4: Icon Buttons Without Labels

The social icons, theme switcher, mobile menu button, and copy buttons were all icon-only. Visually clear, but for screen reader users they were announced as just "button" — no indication of what they do.

The fix is always the same: add aria-label to the button describing the action, and add aria-hidden="true" to the icon inside it so screen readers skip the SVG entirely.

// Before
<IconButton onClick={toggleTheme}>
  <Sun />
</IconButton>

// After
<IconButton
  onClick={toggleTheme}
  aria-label="Switch to light mode"
>
  <Sun aria-hidden="true" />
</IconButton>

Fix 5: Contrast Ratios — When Gray Is Too Light

WCAG 2.1 requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text. I was using Tailwind's text-gray-400 (rgb 156, 163, 175) for date labels and meta text at small sizes — text-xs and text-[11px]. That fails at 3.1:1.

Bumping to text-gray-500 (rgb 107, 114, 128) passes at all sizes with a ratio of 4.6:1. One class name change, no visual impact most people would notice, but a meaningful improvement for users with low vision.

The Final Results

After two branches of changes merged into main and deployed to Vercel, here is what Lighthouse reported:

Performance: 98 (up from 85)

Accessibility: 100 (up from 85)

Best Practices: 100 (unchanged)

SEO: 100 (up from 97)

The Takeaway

Most accessibility and SEO issues on modern Next.js apps are not deep architectural problems. They are small, specific things that got overlooked during development — buttons that needed one attribute, a heading that was the wrong element, a file that needed to exist.

Run Lighthouse on your site right now. Open DevTools, go to the Lighthouse tab, hit Analyze. I guarantee you will find at least three things worth fixing. Most of them will take under ten minutes each.

Your users — especially the ones using assistive technology — will thank you. And so will Google.

Back to all posts
Thanks for reading 🙏