diff --git a/.changeset/shaggy-comics-fail.md b/.changeset/shaggy-comics-fail.md
new file mode 100644
index 000000000000..981a25c978d6
--- /dev/null
+++ b/.changeset/shaggy-comics-fail.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: `append_styles` in an effect to make them available on mount
diff --git a/.changeset/wise-hairs-pay.md b/.changeset/wise-hairs-pay.md
new file mode 100644
index 000000000000..7d96c1daab15
--- /dev/null
+++ b/.changeset/wise-hairs-pay.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: always inject styles when compiling as a custom element
diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js
index d407b4455639..cd44fd998aed 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/index.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/index.js
@@ -451,6 +451,8 @@ export function analyze_component(root, source, options) {
}
}
+ const is_custom_element = !!options.customElementOptions || options.customElement;
+
// TODO remove all the ?? stuff, we don't need it now that we're validating the config
/** @type {ComponentAnalysis} */
const analysis = {
@@ -500,13 +502,13 @@ export function analyze_component(root, source, options) {
needs_props: false,
event_directive_node: null,
uses_event_attributes: false,
- custom_element: options.customElementOptions ?? options.customElement,
- inject_styles: options.css === 'injected' || options.customElement,
- accessors: options.customElement
- ? true
- : (runes ? false : !!options.accessors) ||
- // because $set method needs accessors
- options.compatibility?.componentApi === 4,
+ custom_element: is_custom_element,
+ inject_styles: options.css === 'injected' || is_custom_element,
+ accessors:
+ is_custom_element ||
+ (runes ? false : !!options.accessors) ||
+ // because $set method needs accessors
+ options.compatibility?.componentApi === 4,
reactive_statements: new Map(),
binding_groups: new Map(),
slot_names: new Map(),
diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js
index 124438a9dab0..a56aca9c5f0b 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js
@@ -621,8 +621,9 @@ export function client_component(analysis, options) {
);
}
- if (analysis.custom_element) {
- const ce = analysis.custom_element;
+ const ce = options.customElementOptions ?? options.customElement;
+
+ if (ce) {
const ce_props = typeof ce === 'boolean' ? {} : ce.props || {};
/** @type {ESTree.Property[]} */
diff --git a/packages/svelte/src/internal/client/dom/css.js b/packages/svelte/src/internal/client/dom/css.js
index 52be36aa1f46..8e6faa0e32dc 100644
--- a/packages/svelte/src/internal/client/dom/css.js
+++ b/packages/svelte/src/internal/client/dom/css.js
@@ -1,6 +1,6 @@
import { DEV } from 'esm-env';
-import { queue_micro_task } from './task.js';
import { register_style } from '../dev/css.js';
+import { effect } from '../reactivity/effects.js';
/**
* @param {Node} anchor
@@ -8,7 +8,7 @@ import { register_style } from '../dev/css.js';
*/
export function append_styles(anchor, css) {
// Use `queue_micro_task` to ensure `anchor` is in the DOM, otherwise getRootNode() will yield wrong results
- queue_micro_task(() => {
+ effect(() => {
var root = anchor.getRootNode();
var target = /** @type {ShadowRoot} */ (root).host
diff --git a/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune-access-injected-css/_config.js b/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune-access-injected-css/_config.js
new file mode 100644
index 000000000000..99a223492b8b
--- /dev/null
+++ b/packages/svelte/tests/runtime-browser/custom-elements-samples/host-rune-access-injected-css/_config.js
@@ -0,0 +1,21 @@
+import { test } from '../../assert';
+const tick = () => Promise.resolve();
+
+export default test({
+ async test({ assert, target }) {
+ target.innerHTML = '