all posts
May 20, 2026·4 min read·uxportfolioconversion

Hide the price: making a portfolio's 'Hire me' section opt-in

A small UX bet that pricing should be revealed on intent, not pushed at every visitor who lands on the home page.

My portfolio home page used to lay out my full pricing grid to everyone who scrolled far enough — every engagement type, every starting price, in full. It felt thorough. It also felt like a sales pitch shoved in front of people who weren't shopping. Most visitors to a portfolio are not buyers. They're recruiters skimming, peers reading the blog, someone who clicked a link from a tweet. Showing all of them a price sheet reads as "I'm selling," and that posture quietly cheapens everything above it on the page.

So I made a bet: pricing should be revealed on intent, not broadcast by default.

The observation

Maybe 5% of home-page visitors are evaluating me for paid work. The other 95% are doing something else, and for them the pricing block answers a question they never asked. Worse, it sets a transactional tone. The work — the case studies, the lab, the writing — should be what carries the page. Pricing is the thing you go look at once you've decided you might want to hire someone, and almost nobody decides that from the home page in one scroll.

The dedicated /services page is a different story. If you navigated there, you arrived with intent. Hiding anything from that audience would be obnoxious — they came to see the prices, so the prices should be right there, immediately, no clicks.

The bet

Same component, two behaviours. On the home page, the Services section collapses to a compact teaser: how many engagement types I take, a one-line summary, and a small monospace line that says exactly what to expect — fixed-price · milestone-billed · pricing inside. There's a single "View services & pricing" button that expands the full grid in place, plus a link to the full page for anyone who'd rather go there.

On the /services route the section renders fully expanded from the first paint. No teaser, no reveal — you asked, here it is.

The teaser is honest about what it's hiding. It says pricing is inside; it isn't coy or clickbaity. The point isn't to manufacture a click, it's to not waste the attention of the 95% while keeping pricing one obvious tap away for the 5%.

The implementation

This is deliberately tiny — one prop, one piece of state. The component takes a collapsible prop that defaults to false, and initializes its open state from it:

type Props = {
  collapsible?: boolean;
};
 
export function Services({ collapsible = false }: Props) {
  const [open, setOpen] = useState(!collapsible);
  // ...
}

The default of false is the safe one: anywhere the component is dropped in without thinking, it shows everything. The route page renders it plain, so it's fully expanded. The home page passes collapsible to opt into the teaser, and starts collapsed because open initializes to the negation of the prop. Clicking "View services & pricing" just flips open to true and the full grid mounts in place.

The thing I was careful not to break: the section keeps its heading and its #services anchor in both modes. Any link or scroll-spy or nav item pointing at #services lands in the same spot whether the grid is collapsed or open. The collapse is purely about the pricing detail underneath the heading; the section's identity on the page is unchanged. Nothing downstream had to know this feature exists.

Why this isn't hiding value

It would be easy to read "hide the price" as a dark pattern — bait people into a click to see numbers. That's the opposite of the intent, which is why the teaser states up front that pricing lives inside and the full page is one link away. Nothing is gated; nothing is gamed.

The real principle is about respecting attention. A price the moment you arrive assumes you're a buyer. Most people aren't, and treating every visitor as a lead is how a portfolio starts to feel like a landing page. Revealing pricing on intent says: the work speaks first, and the commercial details are here for you the moment you want them. That's a better posture for the 95% and, I'd argue, for the 5% too — they get a calmer page and the same one-tap access to exactly what they came for.

It's a small change. One prop, one bit of state, an anchor left intact. But the bet behind it — show the price on intent, not on arrival — is the kind of small UX opinion that quietly changes how the whole page reads.