June 2024 – October 2025 · Platform modernization · Power Pages · Bootstrap · Azure AD B2C

Hub Platform Modernization

Five projects on one platform over about a year and a half, none of them planned as a single initiative. A Power Pages data-model migration was required to unlock Bootstrap 5, which triggered a front-end rebuild and surfaced accessibility debt. In parallel, the Azure AD B2C sign-up and sign-in flows still didn’t match the new visual system, and a long-standing spinner inconsistency needed fixing. I worked on every part of it.

Role
Design for the visual system upgrade, and front-end development for the Bootstrap rebuild, the Azure AD B2C flows, and the spinner fix. The Power Pages data-model migration was backend platform work and not mine, but it’s the reason the other four efforts had to happen.
Team
The Hub platform team, throughout. This case study covers my contribution across five connected efforts, not the full program.
Timeline
June 2024 – October 2025, four phases (see below), each taken up as it became the next blocker, not on a planned schedule.
Status
Shipped, every piece in production
Scope
~20 pages · 14+ components · 6 side panels · 4 modals · 3 forms · 11 Azure AD B2C flows

Detailed UI masked per NDA. Process artifacts and metrics shared with permission.

Summary

  • Problem. A Power Pages data-model migration was required to unlock Bootstrap 5, which forced a full front-end rebuild and surfaced 35 WCAG Critical/Serious violations, mismatched Azure AD B2C flows, and three uncoordinated loading spinners.
  • Role. Design for the visual system upgrade; front-end development for the Bootstrap rebuild, the 11 Azure AD B2C flows, and the spinner consolidation.
  • Impact. 35 → 0 WCAG violations remediated. 14 of roughly 20 page-level CSS files consolidated into one token-based stylesheet. All five efforts shipped to production.
  • Stack. Bootstrap 3→5 · Power Pages · Dynamics 365 · Azure AD B2C · Deque Axe

Why one upgrade became five projects

Power Pages ran on Bootstrap 3 from 2014 until Microsoft added Bootstrap 5 support in 2023, available only on the platform’s enhanced data model. Bootstrap 5 could not run on the older standard data model. That meant the Hub platform’s Bootstrap upgrade, which touched every page and component, could not begin until the data model was migrated. The accessibility work that followed traces directly to that dependency. The Azure AD B2C flows and the spinner cleanup do not: they happened on the same platform around the same time, but neither was blocked by the data-model migration.

The Power Pages migration itself was not my work. It moves site configuration from custom Dataverse tables into Microsoft’s standard solution tables, giving faster provisioning and removing the need for manual package updates. It’s included here because the four sections that follow depend on it.

Bootstrap 3 to 5: the rebuild, not a patch

Microsoft provides a migration tool for the Bootstrap 4-to-5 jump. It handles the known breaking changes, mainly renaming data attributes across interactive components (data-toggle to data-bs-toggle, and similar). It does not account for custom code built on top of those classes. Running the tool broke pages: years of styling had accumulated across global CSS, page-level CSS, and inline styles with no consistent pattern, so the tool converted each case differently and left some components structurally broken.

We decided to rebuild the front end from scratch rather than fix what the tool produced. The visual design stayed close to the existing product; we cleaned it up and used space more efficiently without redesigning it. Every line of HTML and CSS was rewritten rather than patched. The main risk was the JavaScript and Dynamics 365 backend wired into that markup: a missed class name or element ID could silently break a working feature behind a page that still looked correct. We kept the old codebase as a reference and verified every wired connection against it manually. Two of us carried this out, neither a professional developer, on a live D365-backed platform, in 2024, before AI coding assistants were part of standard workflow.

There were no visual regressions, because nothing remained to regress to. We removed fourteen of roughly twenty page-level CSS files and consolidated what remained into a single global stylesheet built on CSS variables. A color or type change that previously required searching a dozen files now takes editing one token.

This rebuild is also where Blueprint Design System originated. The same button appeared in four different visual forms across the platform, because components had inconsistent HTML structures and pulled styling from inline, page-level, and global sources at once. We resolved this one component at a time, and that process became the basis for Blueprint’s token-based system. That case study covers where the system went from there.

Accessibility: from fixing flags to fixing patterns

Testing the rebuilt front end with Deque Axe identified 35 Critical and Serious violations: 8 Critical, 27 Serious. The task was not only to close each flagged issue, but to identify the underlying pattern so the same mistake would not recur.

The hardest category was focus order, controlled by tabindex. The straightforward fix, assigning an explicit numeric value to every focusable element, is also the most fragile: it locks in a fixed sequence, and any later change, such as a new component or a reordered section, risks breaking that sequence or skipping a required element. WCAG 2.4.3 exists to address exactly this. The more durable solution follows the DOM’s natural order instead of overriding it. It takes more effort upfront but is far less likely to break silently later.

We tested the fixes ourselves first, then ran a formal QA pass with Axe, signed off by the QA accessibility tester. The longer-term change was that aria labels, alt text, and related accessibility work were built in from the start on everything developed afterward, so QA now catches regressions before release rather than after.

Azure AD B2C: styling what you can’t see

Eleven flows in total: registration, sign-in, forgot password, MFA verification and its variants, email and password changes, terms acceptance, and feedback and issue reporting. These pages already ran on Bootstrap 5, so the issue was not a version gap. It was years of inline styling: the same component styled inconsistently across flows, broken layouts, and branding that no longer matched the rest of the platform.

The core constraint is architectural. Azure AD B2C renders these pages by merging custom hosted HTML with its own injected form controls, the actual input fields, buttons, and validation logic, at runtime in the user’s browser. The source file contains only a shell and a placeholder div; the interactive elements that need styling don’t exist in any file that can be opened and read. The only way to determine their structure is to render the page, inspect the live DOM, and write CSS and JavaScript based on what’s found. Microsoft’s documentation notes that any JavaScript hooked to these elements requires pinning a specific page layout version, since Microsoft can otherwise change the injected markup without notice.

This was a harder problem than a standard styling pass, and it was also my first fully solo build, covering design and code from start to finish. It took two weeks. Pairing with QA during development, rather than waiting for a full QA cycle, kept the later testing pass short. Some of the accessibility issues from the previous section also appeared here and were fixed the same way.

Spinner standardization: the loose end

Three different spinners had accumulated with no coordination: FontAwesome’s, bundled with Power Pages by default; Fluent UI’s, introduced through Microsoft D365 integrations and iframes; and a custom spinner built by a developer for one specific feature. No one had defined what a loading state should look like or behave like on the platform.

I documented every instance’s markup and styling, then used GitHub Copilot to trace each spinner back to where and how it was called before deciding on a replacement plan. Bootstrap’s own spinner became the target, since it was already the most compatible option with the rebuilt front end. Execution differed by origin: FontAwesome’s spinners required a small JavaScript swap from fa-spin to Bootstrap’s spinner-border classes, the custom spinner was replaced outright, and Fluent UI’s required its own JavaScript replacement since no equivalent class-based swap existed. The consolidation reduced an estimated 10-day standardization effort to 5 days.

This should have shipped with the original Bootstrap rebuild. It didn’t, for the same reason most of these efforts were spread out: there wasn’t enough time or in-house expertise to take it on alongside everything else at once. It landed over a year later, on its own, but remains part of the same upgrade.

Outcomes

Everything covered here shipped to production, with no exceptions.

What I’d do differently

Document the work while it’s still fresh. This write-up came more than a year after some of the work happened, which meant reconstructing decisions and constraints from memory rather than notes. The most useful details, the ones that explain a decision rather than just describe it, are also the first to be forgotten.

This project marked the shift from being seen as a visual designer to being able to work and communicate like a developer. That shift is reflected across every section above.