They Asked Me to Build a Slider. It Was a Much Better Question Than I Thought.

I sat down for a technical interview recently and got handed this: here's a React page, here are ten image URLs from the internet, build a slider. Next button, previous button, a row of dots underneath. Click a dot, jump straight to that slide. No animation needed.
My honest first reaction was is this it? I'm an architect. I'd come in expecting to defend some structural decision, argue about boundaries, maybe get grilled on a system design. Instead I got a task I'd have called kindergarten-level on paper.
Then I started typing, and about thirty seconds in I got genuinely interested — not in the slider, in what the slider was doing to me.
The first thirty seconds
Before writing anything I asked questions. Do you want keyboard support? Should it wrap around? Do the images need preloading? Some of those got a no, don't worry about it. Fine — that's an answer, and now the scope is pinned down instead of assumed.
Then I opened the component and the first thing I wrote was state:
const [currentSlide, setCurrentSlide] = useState(0);
One value. That's all this thing needs to know about itself — which slide is showing. Everything else is derived.
And the second thing I wrote was three empty functions:
const handleNext = () => {}; const handlePrevious = () => {}; const handleSelectSlide = (index: number) => {};
Empty. Nothing inside them. I hadn't decided the boundary behavior yet, hadn't written a single div. I just named the three things this component can do, and then kept going.
I want to be careful here, because this is the part I actually find interesting and it would be easy to oversell. I'm not claiming that's the One True Order. But sitting there, watching myself do it, I realized I had described the entire component — its state and its complete behavior surface — before rendering anything. The markup afterwards was almost mechanical. There was nothing left to decide.
The interesting part of a trivial task isn't whether you finish it. It's what you reach for first.
The same task, three ways
I've never sat on the other side of the table scoring people on this, so take what follows as a hypothesis rather than a verdict. But I think this task separates approaches cleanly, and the separation has nothing to do with knowing React.
Start from the markup. Drop in a div, put an img in it, add two buttons. Then wire up the next button — oh, that needs a handler, scroll back up, write one. That needs state — scroll up again, add useState. Then the dots, which need to know the active index, which means going back to think about what the index actually means. The code arrives, but it arrives by accretion, each piece pulling the previous one apart a little.
Start from the pieces, one at a time. State first, then a handler, then the markup for that handler, then the next handler. Better — but each behavior is decided in isolation, so the boundary rules ("what happens at the last slide?") get discovered one at a time, in the middle of writing JSX, when you're least set up to think about them consistently.
Start from state and behavior as a set. One useState, three named handlers, all declared before anything renders. The boundary question surfaces immediately and gets answered once, for all three, because they're sitting right next to each other. Then you render.
The difference isn't skill with React. All three people finish. The difference is whether the shape of the component was decided up front or discovered by bumping into it, and that is the thing this dumb little task exposes with surprising precision.
Then they made it worse, and that's when it got good
Part two: show three images per page instead of one. And add looping — from the last page, next goes to the first; from the first, previous goes to the last.
That sounds like a small tweak. It isn't, and this is the bit I enjoyed.
In the one-image version, the natural move at the end is to disable the button:
<button onClick={handleNext} disabled={currentSlide === images.length - 1}> Next </button>
The boundary is handled in the markup, as a disabled state. Now change the rules. With three-per-page and wrapping, "the end" isn't the last image anymore, it's the last page — and there's no such thing as the end, because it wraps. The button is never disabled. The logic moves out of the JSX and into the handler:
const pageCount = Math.ceil(images.length / imagesPerPage); const handleNext = () => { setCurrentPage((page) => (page + 1) % pageCount); }; const handlePrevious = () => { setCurrentPage((page) => (page - 1 + pageCount) % pageCount); };
Two things changed underneath, and neither is visible in the requirement as stated. The unit of state stopped being which image and became which page, which is a different concept that happens to look the same on screen with ten images and one per page. And the boundary rule migrated from a rendering concern to a behavioral one.
If your first version had the wrapping logic smeared across the JSX, this is where you pay. If it was already sitting inside three named handlers, you edit two lines.
Ten images, three per page, and suddenly the task has an actual opinion about your first draft.
Say it out loud or none of this counts
Here's the thing that makes the whole exercise work, and it's not the code.
Nobody watching can see you reason. They see a cursor. So I narrated the entire time: I'll start with state — I think all I need to store is which slide is selected. Now the handlers. I'm not going to build arrow-key navigation unless you want it, just next and previous buttons. And the answer came back: yeah, that's fine, don't bother.
That exchange took four seconds and it removed a chunk of work I would otherwise have guessed at. More importantly, it made my reasoning visible. Someone watching me could tell why the code was landing in that order, which is information they cannot get any other way.
This is the same argument I made in the piece on interviewing senior engineers from the interviewer's side: the signal is in the reasoning, not the artifact. Sitting on the candidate side of it, I'd put it even more bluntly. If you think silently and produce correct code, you've handed over the least interesting half of what you know.
And yes, I used Google
At one point I needed to iterate a fixed number of times to render the dots. The simplest thing is:
{Array(pageCount).fill(0).map((_, index) => ( <Dot key={index} active={index === currentPage} onClick={() => handleSelectSlide(index)} /> ))}
And I blanked on it. Couldn't remember how to make an empty array of a given length. So I asked whether I could look it up, they said sure, I looked it up, and moved on.
I'd like that to be unremarkable, because it should be. Forgetting a piece of syntax you type maybe twice a year says nothing about anything. What would actually have mattered is if I hadn't known what I was reaching for — that I needed a fixed-length iteration, that the dots derive from page count rather than being their own state. That part I never doubted. The incantation to produce the array is a lookup.
The failure mode isn't forgetting an API. It's not knowing what shape of thing you need.
What I took from it
I don't know how the interview went. Genuinely — no result yet, and I'm writing this without one.
But I came away thinking the task was much smarter than it looked, and I'd been slightly snobbish about it in the first minute. A hard problem mostly tells you whether someone has seen that problem before. A trivial problem, watched closely, tells you the order someone's mind moves in — and then a small twist tells you whether their first draft was structured or just correct.
The slider was never the point. It was a transparent object they could watch me think through, and it cost them ten minutes to set up.
If you're interviewing people and reaching for something elaborate, I'd at least consider the opposite: take something almost insultingly simple, watch the first thirty seconds, then change one requirement. And if you've been on the receiving end of a task like this and read it as disrespect — I did too, briefly. I'd like to hear whether you changed your mind the way I did.
More than a blog post
I share frontend news and the reasoning behind it throughout the day. Pick the language that feels natural to you.