MooApp
What is MooApp?
MooApp is the set of npm packages I use as the foundation for every React single-page app I build. It bundles a design system, an application framework, and an icon library, so a new project can talk to an authenticated API and render its first screens without a lot of upfront wiring. It is a TypeScript monorepo, published to npm under the @andrewmclachlan/moo-* scope.
Why I built it
Every time I started a new SPA, I found myself reaching for the same set of things - MSAL for Azure AD authentication, React Query for server state, Axios for HTTP, React Router for navigation, a Bootstrap-flavoured component library, an app shell with a header and a sidebar, and the same handful of forms and tables I'd built a dozen times before. Each project would re-invent the wiring, and inevitably each project would solve the same edge cases slightly differently.
The pain points stacked up:
Hooking MSAL into an Axios interceptor is fiddly. Getting it right on a hard refresh, where requests can fire before the interceptor is attached, is worse.
React Query is great, but every project ended up with its own slightly different
useApiGet/useApiPostwrappers.The same app-shell layout - header, sidebar, error boundary, notifications, modal host - kept getting rebuilt from scratch.
Components I'd written for one project - a sortable paginated table, a ComboBox, a Section with a configurable header level - never made it into the next one.
MooApp is my answer to all of that. Pull the boring, shared parts into versioned, peer-dependency-friendly libraries so the next project starts a long way past zero.
How it works
The repository is an npm workspaces monorepo with three publishable packages that layer on top of each other, plus a demo app and a Storybook documentation site:
@andrewmclachlan/moo-ds is the design system. It is the foundation - React components, layout primitives, providers and utility hooks - with no authentication concepts in it at all. ComboBox, DataGrid, Section, Alerts, Notifications, the Theme and Link providers, and hooks like
useLocalStorage,useSessionStorageanduseClickAwayall live here.@andrewmclachlan/moo-app builds on moo-ds to provide the full authenticated SPA framework. The
MooApproot component wires up MSAL, React Query, the HTTP client and the rest of the provider stack in the right order.MooAppLayoutdrops in a header, sidebar, error boundary and notification host.HttpClientProviderexposes a shared Axios client that automatically attaches an MSAL access token to every request, and theuseApiGet/useApiPost/useApiPut/useApiPatch/useApiDeletehooks wrap React Query so calling an API is a one-liner.@andrewmclachlan/moo-icons compiles a curated set of SVGs into tree-shakeable React components via SVGR.
demoo is the demo app I dogfood the libraries against.
storybook is the documentation site - every component has a story with live controls.
A few deliberate choices keep the day-to-day experience friction-free:
Vite library mode with
vite-plugin-dtsemits ESM bundles and TypeScript declarations for each library. Peer dependencies (React, MSAL, React Query, React Router) are externalised viarollup-plugin-peer-deps-external, so consuming apps stay in control of their own versions.Vite aliases in demoo and storybook resolve
@andrewmclachlan/moo-*imports straight to the library source. Editing a component and seeing the change in the demo app or in Storybook needs no rebuild.The MSAL interceptor in HttpClientProvider uses
useLayoutEffectwith refs to avoid a race condition that bit me early on, where on a hard refresh requests would fire before the interceptor was attached and the API would 401.Component type checking in compound components like
Section.HeaderandComboBox.Itemis done bydisplayNamestring rather than reference identity, which side-steps a monorepo problem where the same component imported through two different module paths fails an===check.
What it gives you day to day
One import for an authenticated SPA -
<MooApp>handles MSAL, React Query, the HTTP client and the provider stack in the right order, so a new project never has to get that wiring right by hand.API hooks that just work -
useApiGet<Foo>("/api/foos")gives you a typed, cached, MSAL-authenticated request with no boilerplate.A standard app shell -
<MooAppLayout>drops a header, sidebar, error boundary and notification host into your layout, ready for your routes.A growing component library - tables with sortable headers and pagination, a ComboBox with a compound API, Section wrappers with configurable header levels, modal and notification systems.
Storybook for everything - every component is documented and explorable with live controls.
MooApp is open source and under active development. The current focus is dropping the React Bootstrap dependency in favour of custom components, for a smaller bundle and more design control. Source code and releases are on GitHub.