diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts index 6ccf02c4fa6..a180266bf21 100644 --- a/packages/runtime-dom/__tests__/customElement.spec.ts +++ b/packages/runtime-dom/__tests__/customElement.spec.ts @@ -546,6 +546,24 @@ describe('defineCustomElement', () => { const style = el.shadowRoot?.querySelector('style')! expect(style.textContent).toBe(`div { color: red; }`) }) + + // #6530 + test('style with nonce for content security policies (CSP)', () => { + const Foo = defineCustomElement({ + nonce: 'noce-string-for-csp-policy', + styles: [`div { color: red; }`], + render() { + return h('div', 'hello') + } + }) + + customElements.define('my-styles-nonce', Foo) + container.innerHTML = `` + + const el = container.childNodes[0] as VueElement + const style = el.shadowRoot?.querySelector('style')! + expect(style.getAttribute('nonce')).toBe('noce-string-for-csp-policy') + }) }) describe('async', () => { diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index 1e551cc05da..4a318be028a 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -164,7 +164,10 @@ const BaseClass = ( typeof HTMLElement !== 'undefined' ? HTMLElement : class {} ) as typeof HTMLElement -type InnerComponentDef = ConcreteComponent & { styles?: string[] } +type InnerComponentDef = ConcreteComponent & { + styles?: string[] + nonce?: string +} export class VueElement extends BaseClass { /** @@ -411,6 +414,9 @@ export class VueElement extends BaseClass { styles.forEach(css => { const s = document.createElement('style') s.textContent = css + // nonce string for content security policy + // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/nonce + this._def.nonce && s.setAttribute('nonce', this._def.nonce) this.shadowRoot!.appendChild(s) // record for HMR if (__DEV__) {