◆ Emotion は ShadowDOM に対応していない
◆ style タグを追加するコンテナを指定できるので ShadowRoot 内の何処かに指定すれば動く
  ◆ Emotion キャッシュを CustomElement の要素ごとに作るのでムダも多め
  ◆ Emotion の動作的に全体で共通の CSSStyleSheet が 1 つあれば大丈夫なはず
◆ 試してみたけど style タグからの作成は adoptedStyleSheets に設定できない
◆ 無理やりやって動かすことはできたけど 標準機能で CSSStyleSheet 対応を待ちたい

以前 lit-html で Emotion を使いましたが lit-element でも使いたいです
ですが Emotion はグローバルな CSS が前提になっています
css 関数を使うと自動でグローバルな style タグが更新されていきます

コンテナの style タグの CSSStyleSheet を使う

カスタムするには createEmotion 関数を使って自分で Emotion インスタンスを作ればいいらしいです
しかし カスタムできると言ってもスタイルの書き込み場所関係では container を指定できるくらいです
デフォルトだと document.head に作られる style タグを 任意の div などの要素に変更できるだけです

CSSStyleSheet を渡せばそれにスタイルを追加していってくれるといいのですが そういう機能は用意されていませんでした
となると自分で style タグから CSSStyleSheet を取り出してセットすればいいかと試してみました

import createEmotion from "https://unpkg.com/@emotion/css@11.10.0/create-instance/dist/emotion-css-create-instance.esm.js?module"
import { LitElement, html } from "https://www.unpkg.com/lit@2.4.0?module"

const div = document.createElement("div")
const { css } = createEmotion({ key: "css", container: div })
document.body.append(div)
css({ color: "red" })
const style = div.querySelector("style")
const sheet = style.sheet
div.remove()

document.adoptedStyleSheets = [sheet]

customElements.define("elem-1", class extends LitElement {
static get styles() {
return [sheet]
}

render() {
return html`
<div class=${css`color: blue`}>BLUE</div>
`
}
})

しかし

Failed to set the 'adoptedStyleSheets' property on 'Document': Can't adopt non-constructed stylesheets.

というエラーでした
style タグから作られた CSSStyleSheet は adoptedStyleSheets に使えませんでした
Emotion は同じスタイルなら同じクラス名になるようにしてくれるので CSSStyleSheet を各 CustomElement のインスタンスや CustomElement 間で分ける必要がなくてひとつの CSSStyleSheet をすべての場所の adoptedStyleSheets に追加するだけで済んでよさそうだったのですけどね

個別に createEmotion

そうなると各 CustomElement のコンストラクタで毎回 createEmotion して container に ShadowRoot 内の要素を指定するしかないです
ただ lit-element だと container の要素の作成は render 処理の結果行われるものですが render の中で css 関数を呼び出すのでその時点で container が connected である必要があります
lit の通常の機能でできないのはイマイチですが 先に container にする div を作って置いて ShadowRoot が作られたときに追加しておき render では関与しないようにします
LitEmotionElement と別のクラスを作ってそれを継承することにしました

<!doctype html>

<script>
window.process = { env: { NODE_ENV: "production" } }
</script>
<script type="module">
import createEmotion from "https://unpkg.com/@emotion/css@11.10.0/create-instance/dist/emotion-css-create-instance.esm.js?module"
import { LitElement, html } from "https://www.unpkg.com/lit@2.4.0?module"

const LitEmotionElement = class extends LitElement {
constructor() {
super()
this.emotion_container = document.createElement("div")
const { css } = createEmotion({ key: "css", container: this.emotion_container })
this.css = css
}

connectedCallback() {
super.connectedCallback()
this.renderRoot.prepend(this.emotion_container)
}
}

customElements.define("elem-1", class extends LitEmotionElement {
static get properties() {
return {
pos: { type: Number },
}
}

constructor() {
super()
this.pos = 0
}

render() {
return html`
<div class=${this.css`display: flex`}>
<div class=${this.css`color: green`}>
GREEN
</div>
<div class=${this.css`color: purple`}>
PURPLE
</div>
</div>
<div>
<input type="range" min="0" max="100"
.value=${this.pos}
@input=${event => this.pos = event.target.value}
>
</div>
<div>
<div class=${this.css`
background: red;
width: 50px;
height: 50px;
border-radius: 50%;
position: relative;
left: ${this.pos}px;
`}></div>
</div>
`
}
})
</script>

<elem-1></elem-1>

これで動きはするのですけど個別の処理はなんかムダが多く CustomElement の数が増えるとパフォーマンス面での心配もあります

無理やり

やっぱり最初の方法でやりたいなと思うので試しに無理やりやってみました
内部処理的に style タグを経由して sheet プロパティにアクセスしてスタイルを追加しています
style タグの追加時にダミーの style タグと置き換えます
sheet プロパティに new CSSStyleSheet で作ったインスタンスを持つオブジェクトにします
ルール数が 65000 を超えると新しい style タグを作るようになっているのでそれを超えるとうまく動かないです
また flush の処理も考慮してないので使うと動きません

<!doctype html>

<script>
window.process = { env: { NODE_ENV: "production" } }
</script>
<script type="module">
import createEmotion from "https://unpkg.com/@emotion/css@11.10.0/create-instance/dist/emotion-css-create-instance.esm.js?module"
import { LitElement, html } from "https://www.unpkg.com/lit@2.4.0?module"

const div = document.createElement("div")
const { sheet, css } = createEmotion({ key: "css", container: div })
sheet.tags.push = function(_tag) {
const fake_tag = { sheet: new CSSStyleSheet() }
Array.prototype.push.call(this, fake_tag)
}
// for create tag
css({ color: "red" })
const css_sheet = sheet.tags[0].sheet

customElements.define("elem-1", class extends LitElement {
static get properties() {
return {
child_num: { type: Number },
}
}

static get styles() {
return [css_sheet]
}

constructor() {
super()
this.child_num = 1
}

render() {
return html`
<div>
<div class=${css`margin-bottom: 10px`}>
<button @click=${this.pushChild}>+</button>
<button @click=${this.popChild}>-</button>
</div>
<div class=${css`display: flex;flex-wrap: wrap`}>
${Array.from(Array(this.child_num)).map(x => {
return html`<elem-2></elem-2>`
})}
</div>
</div>
`
}

popChild() {
this.child_num--
}

pushChild() {
this.child_num++
}
})

customElements.define("elem-2", class extends LitElement {
static get properties() {
return {
color: { type: String },
};
}

static get styles() {
return [css_sheet]
}

constructor() {
super()
this.color = "#eee"
}

render() {
return html`
<div>
<div
@click=${this.changeColor}
class=${css`
width: 120px;
height: 120px;
border: 1px solid #888;
background-color: ${this.color}
`}
></div>
</div>
`
}

changeColor() {
const r = ~~(Math.random() * 256)
const g = ~~(Math.random() * 256)
const b = ~~(Math.random() * 256)

this.color = `rgb(${r}, ${g}, ${b})`
}
})

document.body.append(document.createElement("elem-1"))
</script>

早く style タグを使わないタイプの CSSStyleSheet にも対応してほしいですね