Foundations

  • Secured backoffice Management API endpoints

    Community content on the new Umbraco backoffice almost exclusively covers the UI side — property editors, dashboards, workspace views. The C# endpoints those UIs actually call are consistently under-documented. The BlockRestrictionApiController in this repo is a clean example of the secured backend half: routing under /umbraco/.../api/v1, locking endpoints down with [Authorize(Policy = AuthorizationPolicies.SectionAccessContent)], Swagger doc registration so the endpoints show up in the API docs, and a typed fetch wrapper on the client that pulls the user's backoffice bearer token automatically.

  • Configuration that inherits down the content tree

    A common need in a CMS: attach a piece of configuration to something high up, and have everything below it pick the value up automatically unless it's overridden closer to home. Block Restrictions does it with allowed-block rules — set a rule once, and every page beneath inherits it — but the shape is general. This tutorial is the resolution engine behind that: how to attach a rule, resolve it for any node by walking up the tree, cache the answer so you're not re-walking on every request, and fail open when nothing is configured. It's the "how rules resolve" half of the Block Restrictions trio; the editor-wrapping refinement is what consumes the answer.

  • Building a touch-friendly drag-to-scroll slider in vanilla web components

    Carousel libraries like Swiper and Embla are great until you measure the bundle cost. This tutorial will walk through the <dc-slider> component in this repo — a small Lit web component that supports touch drag (follows the finger and snaps to the nearest slide on release), desktop hover-zone navigation, and explicit arrow buttons as an opt-in. The aim is to show what a usable scroller looks like when it's built from scratch with native APIs rather than pulled in as a dependency.

  • Building an inline SVG TagHelper for Umbraco

    SVGs are wonderful for icons and brand marks — small, sharp, infinitely scalable — but only if you can actually style them from CSS, and that's where things tend to get fiddly. This tutorial walks through the <svg-src> TagHelper that the Umbraco Community site uses to inline SVG files from Umbraco media straight into the rendered Razor view, where CSS and JavaScript can then reach inside them. It's a foundation piece — most of the SVG-related tutorials in this suite build on top of it.

  • Polite animation with IntersectionObserver, requestAnimationFrame, and reduced-motion

    The <dc-image-slider> component auto-scrolls a row of images — but you don't want it to keep burning a CPU core when the user can't see it, or when they've asked the OS to dial down motion. This tutorial will walk through the small composition that makes the animation cheap and polite: requestAnimationFrame for the loop itself, IntersectionObserver to pause when the slider scrolls off-screen, visibilitychange for tab switches, and prefers-reduced-motion for accessibility. The general lesson is how to animate something well without reaching for a library.

  • Resolving content in a multi-tenant Umbraco site

    Running multiple sites from a single Umbraco instance is one of those things that looks easy until you've shipped one — and then suddenly every content lookup needs to know which tenant it belongs to. This tutorial walks through the pattern the Umbraco Community site uses for multi-tenancy (several distinct sites out of one Umbraco instance) and the small set of helpers that keep every content lookup scoped to this request's tenant rather than wandering off into another one's tree.

  • Progressive enhancement of async-rendered DOM with MutationObserver

    Progressive enhancement has a tidy mental model: the server sends working HTML, and your JavaScript layers extra behaviour on top once it loads. That model quietly assumes the HTML you want to enhance is there when your code runs. But what happens when it isn't yet — when the very thing you mean to enhance is rendered, asynchronously, by some other component that owns its own timing? Your enhancement runs, finds nothing to do, and gives up. This tutorial walks through the small MutationObserver pattern the Umbraco Community site uses to solve exactly that: the <dc-form-steps> element waits for an Umbraco Forms form to finish rendering, turns it into a multi-step form once it appears, and then disconnects cleanly.

  • A nonce-based Content Security Policy in ASP.NET Core Razor

    A strict Content Security Policy that bans inline scripts will catch most XSS vectors at the browser level — and it will also make life impossible for every legitimate inline script your views happen to emit. The standard answer is to nonce every inline script and stamp the same nonce into the CSP header, so the browser allows scripts whose nonce matches and blocks everything else. This tutorial will walk through the NonceTagHelper + Joonasw integration this site uses, plus a per-request escape hatch for the rare endpoint that needs CSP disabled entirely. CSP-in-.NET is poorly documented; the aim is for this to be the post one of us wishes had existed.

  • One master block data type, restricted per consumer

    This is the content-modelling decision that the whole Block Restrictions package exists to serve, written down on its own because it's the why behind two other tutorials and it's easy to lose under their mechanics. The short version: keep a single Block Grid (or Block List) data type that holds every block the site could ever use, point every document type at that one data type, and then narrow the offered set per consumer — per document type, and by inheritance the content nodes beneath it — with a restriction rule, rather than building a separate data type for every document type that wants a different subset of blocks.

  • Generating utility classes from design tokens with a custom PostCSS mixin

    Utility-first CSS frameworks like Tailwind give you the ergonomics of .pt-md and .mx-xs — but they want to own your design system. The rhythm mixin in this repo flips that arrangement: you write your spacing tokens in root.css as CSS custom properties, hand them to a small postcss-mixins rule, and you get the same utility classes generated for you — driven entirely by your own tokens, with no opinion from a framework. This tutorial will walk through writing the mixin, the modifier suffixes it emits, and how to layer it on an existing PostCSS pipeline.

  • Site search backed by Umbraco's Examine ExternalIndex

    "How do I add search to my Umbraco site?" is a perennial community question, and most answers stop at the single-tenant happy path. This tutorial will walk through the recently-added search on the Umbraco Community site: a SearchPage doc type, a typed SearchService that queries Umbraco's Examine ExternalIndex, a render controller that paginates the results, and the multi-tenant twist — only return hits under the current tenant's content root, so a search on Site A doesn't leak Site B results.

  • Wiring Vite's manifest into Umbraco's Razor pipeline

    Vite bundles your frontend and Umbraco renders your views, and sitting between the two is a single <script> tag that needs to behave completely differently depending on where it's running. Locally, you want the browser talking to the Vite dev server so you get hot module replacement (HMR — your edits to JS and CSS show up in the browser without a full page reload). In production, you want it loading a content-hashed file whose name changes with every build. Same tag, two different use cases. This tutorial walks through the pair of TagHelpers the Umbraco Community site uses to bridge them — <script vite-src> and <link vite-href> — so that you can write one stable line of Razor and let the C# work out, per environment, whether to point at localhost:5123 for HMR or at the hashed asset named in Vite's manifest.json.