The short version
The library itself asks for nothing unusual. It contains no eval, no new Function, no Worker and no WebAssembly, and the canvas and WebGL components only call getContext — which a CSP does not govern. A client-rendered app that imports ngwr's stylesheet runs under a policy with no escape hatches at all:
# Client-rendered app that imports ngwr's stylesheet.
Content-Security-Policy:
default-src 'self';
script-src 'self';
style-src 'self';
img-src 'self' data: blob:;
font-src 'self';
base-uri 'self';
object-src 'none' The part that does the work is the stylesheet import. Twenty-seven entry points — the animation and canvas components, plus card, cascader, list, lightbox, loading-bar, virtual-scroll, drag-drop and breadcrumbs — declare a styleUrl that re-exports the same styles/_index.scss you get from @use. Angular injects that copy at runtime, and a strict style-src blocks the injection. It does not matter, because the identical CSS is already in your linked stylesheet:
// styles.scss — this is what makes 'self' enough for ngwr.
@use 'ngwr'; // every component, in the linked stylesheet
// …or per component, if you are trimming:
@use 'ngwr/button';
@use 'ngwr/split-text';If you don't import the stylesheet
Then the runtime injection is the only copy, and it needs a nonce.
Those twenty-seven components render unstyled under style-src 'self' if their CSS never reached your stylesheet. Give Angular a nonce and it stamps every style it injects:
// main.ts — only needed if you do NOT import the stylesheet above.
import { CSP_NONCE } from '@angular/core';
bootstrapApplication(App, {
providers: [{ provide: CSP_NONCE, useValue: window.__cspNonce }],
});Importing the stylesheet is the better answer: it is one line, it is the documented install path anyway, and it keeps the CSS out of your JavaScript bundle.
Server-rendered and prerendered apps
The nonce has to come from whatever renders the response — the app root attribute is too late.
Under SSR or prerendering, Angular does not inject component styles from client code. It writes them into the document as <style ng-app-id="ng">, so the browser has already parsed — and, under a strict policy, refused — them before your bundle runs. An ngCspNonce attribute on the app root cannot retroactively allow them; the nonce must be minted per response by the renderer.
# Server-rendered or prerendered: Angular writes component CSS into the
# document as <style ng-app-id="ng"> before any client code runs, so a nonce
# has to be produced by whatever renders the response.
Content-Security-Policy:
style-src 'self' 'nonce-<per-response-random>';
# A statically prerendered site (outputMode: 'static') cannot vary the nonce
# per response. Serve it with hashes, or accept:
Content-Security-Policy:
style-src 'self' 'unsafe-inline'; A statically prerendered site has no per-response step to mint a nonce in, so a nonce there is a fixed string in a cacheable file — which buys nothing. Hashes or 'unsafe-inline' for style-src are the honest options. This is Angular's behaviour, not ngwr's: it applies to your own component styles the same way.
Directive by directive
| Name | Description | Type | Default |
|---|---|---|---|
script-src | 'self' is enough. The library contains no eval, no new Function, no Worker and no WebAssembly — verified by sweeping projects/lib and by running the built site under a policy with none of the escape hatches. | directive | 'self' |
style-src | 'self' is enough if your app imports ngwr's stylesheet. Every component's CSS then lives in your linked stylesheet. Without that import, see the nonce section below. | directive | 'self' |
img-src | data: is needed by <wr-qr> and by <wr-image-cropper> (both hand you a canvas as a data URL); blob: by anything that exports a file, including the table CSV download. | directive | 'self' data: blob: |
connect-src | Only what your own app fetches. The library makes no network calls of its own — WrI18nHttpLoader uses whatever URL you configure, and the icon adapters take the icon data as an argument rather than fetching it. | directive | 'self' |
'wasm-unsafe-eval' | Not needed. No entry point compiles WebAssembly. The canvas and WebGL components (aurora, waves, splash-cursor, click-spark, fuzzy-text, confetti) use getContext and nothing else, which CSP does not govern. | not required | — |
'unsafe-eval' | Not needed. Nothing in the library reaches for the string-to-code APIs. | not required | — |
This site
# ngwr.dev itself, for reference. The extra directive is the docs
# highlighter (shiki compiles an Oniguruma WebAssembly module), NOT the library.
Content-Security-Policy:
script-src 'self' 'wasm-unsafe-eval';
style-src 'self' 'unsafe-inline'; ngwr.dev is prerendered, which is where the style-src relaxation comes from, and it highlights code with shiki — whose Oniguruma engine is a WebAssembly module. Neither applies to the library: nothing you install from ngwr pulls in a highlighter, and 'wasm-unsafe-eval' is never needed to run the components. If you add a highlighter to your own app, that dependency's CSP cost is yours to take on.