Corner Health // A 52-Provider Healthcare Directory in Framer by Tanish MittalCorner Health // A 52-Provider Healthcare Directory in Framer by Tanish Mittal
Built with Framer

Corner Health // A 52-Provider Healthcare Directory in Framer

Tanish Mittal

Tanish Mittal

I rebuilt and now run the provider directory for Corner Health, a US network of independent nurse-practitioner-owned primary care practices in Arizona and Washington. The work spans two no-code platforms at production scale: Framer for find.cornerhealth.com (provider directory and careers) and Webflow for cornerhealth.com (the marketing site). Corner Health's own site reports 35,000+ patient appointments and a 4.95 average provider rating across the network.
Everything below shipped to a live healthcare site that patients use to find a provider and book an appointment.

Design system implementation across a live Framer site

The provider directory and careers pages were still on the old brand while the main Webflow site had moved to the current design system. My job was to bring the Framer site onto that system without touching the marketing site: Poppins throughout, terracotta #AE5440, plum #3C2536, cream and beige surfaces.
The swap was larger than it looked. Most text on the site carried inline font declarations rather than references to a shared text style, so changing the 32 text styles fixed almost nothing. I had to swap the font on roughly 2,525 rich text nodes as well, plus detach a text style preset on component-internal labels that inherited their font from a parent the swap never reached.
The careers pages are React code components inside Framer (Careers.tsx and CareerHero.tsx), where fonts and colours are hardcoded in the source and are not driven by Framer's style system at all. Those needed real code edits, not canvas edits. This is the practical limit of no-code development: a design system only reaches as far as the platform's style layer, and code components sit outside it.
Verification mattered here. Framer serves hashed JS bundles that cache hard, so a query string busts the HTML but not the bundle, and a reloaded browser tab kept showing the old font on button labels that had already been changed. I verified against zero-cache served HTML instead: 0 old-font text nodes, 0 old-brand orange.
The provider directory on the Corner Health design system
The provider directory on the Corner Health design system

Reverse-engineering a closed third-party Framer component

The paid media team wanted ad landing pages that link straight into a pre-filtered directory, for example /find-a-provider?city=phoenix&insurance=cigna. The filter panel on that page is a third-party Framer component with no props, no state API and no URL API. Its selection lives in local React state and is exposed nowhere: not on window, not in localStorage, not through events or context.
So I decompiled the component out of the live JS bundle to find out how it actually works. It scrapes its filter options from hidden layers inside each provider card, then stamps a data-filter-<uid>="match" or "no-match" attribute on every card and shows a card only when every stamp on it reads match. Those attributes are plain DOM and persist independently of React, which is the opening that made an integration possible without forking the component.
I built the integration in three layers, so correctness never waits on React. A small pre-paint script in the site's custom code stamps cards while the HTML is still streaming, so an ad visitor's first paint is already filtered and never flashes the full list. A Framer code override then re-applies the filter through the component's own attribute mechanism as soon as the CMS list exists. A third layer syncs the dropdown labels and checkboxes through the component's React fiber so the controls agree with the list, and hands control back to the visitor the moment they touch a filter themselves. If the markup is ever unrecognisable, the whole thing strips itself and the visitor gets a normal unfiltered directory. It fails open, never blank.
Measured on a real load: the filter applied in the same tick the provider list rendered, at 302ms.
A filtered result: Arizona, Medicare, Spanish
A filtered result: Arizona, Medicare, Spanish
Two findings from that build are worth writing down.
Safari silently did nothing while every Chromium test passed. The element finder gated on getComputedStyle().userSelect === "none", and WebKit only supports the prefixed property while React does not add the prefix, so the finder matched zero elements. Never gate cross-browser behaviour on a computed style that WebKit prefixes.
Ad landing pages open the directory with window.open(url, "_blank"), so it frequently loads in a background tab. Chrome throttles timers there, and Framer does not render the CMS collection at all while the tab is hidden. Any wait with a deadline burns its budget and gives up before the list ever exists, leaving the visitor with an unfiltered page permanently. The fix was three independent signals that never expire: an interval, a MutationObserver, and a visibilitychange listener.

Rebuilding the booking flow across 50+ provider profiles

Every provider previously booked through an in-page scheduler embed keyed to a practice slug. I moved the entire directory onto direct booking links, one per provider, driven by two new fields on the Framer CMS collection and bound to the Book Now button on both the directory card and the provider template. 50 providers went live on the new flow in a single release.
Insurance, booking and quick facts on a provider card
Insurance, booking and quick facts on a provider card

Running a provider directory as an ongoing Framer CMS

I maintain the directory as live client work: 59 provider records, 52 currently live. Onboarding a new provider is end to end, covering bio, headshot, practice logo, insurance carriers, languages, services, city and booking link, then verifying the card and the detail page render correctly on desktop and phone before release.
One detail that catches people: headshots render in two different crops. The directory card is a 150px circle with object-fit cover, and the provider detail page is a 327px square where nothing is clipped. A portrait padded out to square looks fine in the circle and shows obvious bars on the detail page, so source images have to be genuinely square with the head fully inside them.
A provider detail page
A provider detail page

Auditing the data behind the directory

The city field driving the location filter was wrong in a way nobody had noticed, because a stale default value had quietly parked most of the network in one small suburb. I audited every record against the client's authoritative city list and corrected 18 of them, 15 of which were sitting on that default. I also fixed a misspelled city name in place (preserving the enum case id, so no provider record lost its reference), added 8 missing cities, and blanked the city on out-of-state providers per the client's rule.
This is the least glamorous work in the project and the most consequential. A directory filter is only as good as the field it reads, and a patient filtering by city gets a wrong answer silently, with no error to report.

Domain migration

When the directory moved to its own subdomain, every internal link that pointed at / or /about started resolving to the sub-site instead of the marketing site. I repointed 19 primary nodes, which cascaded to around 71 instances across the shared navbar, footer and legacy pages, added a 308 redirect from the directory root to the main site, and removed a deprecated nav item that was still rendering in the mobile menu.
The nav here is a Framer overlay that only mounts on click, so a static fetch of the page HTML shows zero of those links and reports a clean result on a broken menu. All of it was verified in a live browser against rendered DOM, not against fetched source.

Interface work

Also shipped: video testimonials on the case study template, a three-video provider testimonial slider (two-up on desktop, one-up on phone), site-wide hover and cursor states on all 22 button nodes, and a mobile layout fix where provider names were set to auto width with no wrapping and overflowed the phone card.
The hover states are a good example of platform reality beating platform documentation. Scale-on-hover clipped inside the card's overflow, and variant-level hover on that component would not persist, so the working answer was a colour darken applied at the instance level.
The directory and a provider profile on phone
The directory and a provider profile on phone

Stack

Framer (CMS, code components, code overrides, branches, site custom code, redirects), Webflow (design system, CMS, components), React, TypeScript, vanilla JS. Working method throughout: build on an isolated branch, verify in a real browser at real breakpoints, and never publish to a live healthcare site without the client's explicit sign-off.
Like this project

Posted Sep 24, 2026

Ongoing Framer + Webflow retainer for a US primary care network: grew the provider directory from 17 to 52+ and rebuilt booking across every profile.