Have you ever opened the issues tab of an open source project, stared at the list, and closed it?
I have. More than once.
The feeling is always the same: "this is for grown-ups, I'm not good enough to touch it". So you close the tab, go back to your side project, and contributing becomes something you'll do when you're "ready".
Spoiler: you'll never be ready. I started by fixing a footer that broke on mobile.
The project and the bug
TimeConv is a simple time converter: you give it a date and it hands you back UTC, seconds, or whatever timezone you asked for. Static site, hand-written HTML and CSS, no framework.
Issue #41 said the footer broke on mobile. Opened in August 2022. Four people passed through it over the years, diagnosed the problem, agreed with the diagnosis...
And not one of them opened a PR.
That's the kind of issue I recommend if you're starting out: old, already diagnosed by other people, and with nobody working on it. Half the work is done and the odds of duplicating someone's effort are low.
The CSS bug that wasn't a CSS bug
The original code did this:
footer {
position: absolute;
height: 15vh;
bottom: 0;
}
Absolutely positioned footer, pinned to the bottom. Works beautifully — until the page has enough content to scroll. Then the footer floats in the middle of your text, because bottom: 0 is relative to the viewport, not to the content.
The modern fix is the flexbox sticky footer: make body a flex column with min-height: 100vh, and give the footer margin-top: auto, which pushes it into whatever space is left over.
I swapped it, tested it, and... two pages didn't budge.
Here's the part I didn't see coming, and the most useful thing I took from this contribution: margin-top: auto only pushes an element if it's a direct child of the flex container. In credits.html the footer sat four levels deep inside a .row — which is a horizontal flex container. And in utcsecondstodatetime.html it was literally outside <body>.
So I opened the HTML of those two files and found a duplicated <html>, orphan </div>s, and tags closing out of order. The file was broken badly enough that prettier couldn't even parse it.
Which means: the issue was filed as a CSS bug, and no amount of CSS was ever going to fix it without touching the HTML. That's why four people diagnosed it and nobody shipped — the diagnosis was only half right.
Final PR: 7 files, 175 lines added, 174 removed.
The red check that almost killed it
PR opened, and CI lights up: Lint Code Base failed.
The beginner reflex (mine included) is to run prettier --write across the repo and push everything green. Don't. That would have added ~138 lines of reindentation to a 7-file PR, and the reviewer would have had to separate the fix from the formatting.
What I did instead was pull the original files from main and run the linter against them:
npx prettier --check docs/
npx htmlhint docs/
Result: the original files already failed. And utcsecondstodatetime.html on main didn't even parse. htmlhint reported 18 errors on the original versus 0 on mine.
I posted that in the PR, with the output from both sides. That is precisely what unblocked the merge — the maintainer could see the red was inherited instead of taking my word for it.
It's a rule for me now:
An inherited red check gets explained with reproduced evidence, not fixed by growing the PR.
Three weeks after opening it (and one polite ping along the way, because maintainers of small projects do go quiet), I got an "Awesome, LGTM!" and the merge.
Hands on: test a static site in 30 seconds
No Node, no build step, nothing:
git clone https://github.com/ArjunSharda/TimeConv.git
cd TimeConv/docs
python3 -m http.server 8000
Open http://localhost:8000, hit F12, turn on the device toolbar and test at 320, 375 and 768 pixels wide. Test one short page and one long page — a footer bug only shows up in one of them.
That's the entire test loop for a static-site contribution. Really.
"But that's just CSS, it doesn't count"
It counts. And let me lay out both sides, because this choice is yours.
Small project. Upside: the maintainer actually reads your PR, the codebase fits in your head, and you get to close the full issue → PR → merge loop, which is where the learning lives. Downside: little reach, sometimes an inactive maintainer, and a process too informal to teach you rigor.
Large project. Upside: serious CI, hard review, documented conventions — you learn the craft. Downside: long review queues, and a real chance someone fixes the bug before you do (that happened to me on another project, and it's an article of its own).
I don't think there's a right side. I think starting small and moving up is kinder to your motivation.
Wrapping up
Seven files, 175 lines added, zero lines of complex logic. Result: a Contributor badge and a four-year-old issue closed.
What was blocking that issue wasn't technical difficulty. It was that nobody had opened the HTML.
Your turn: open the issues tab of a project you actually use, filter by is:issue is:open sort:created-asc, and look at the oldest ones. One of them is waiting for somebody to open the file.
And if you do it, brace yourself for one thing: the merge isn't the end. After mine landed I got excited and kept poking around the site — and while testing the pages in the browser, I noticed the converters only worked once. A second conversion needed a page reload.
There were two bugs. They hid each other, with a side effect that pushed whatever the user typed straight into their browser history.
That's the next article.
Author's note: this was my first contribution to TimeConv, merged in August 2026. I'm documenting every open source contribution I make in this series. If you contribute to open source too, I'd like to hear about it.



Top comments (0)