feat: add useComputedStyle hook - #61
Conversation
Adds a main-thread hook that reads computed CSS property values via element.getComputedStyles() and forwards them to the React background thread. This enables CSS var() values to be used in component props like current-color and tint-color that only accept plain strings. Co-authored-by: TRAE CLI <traecli@bytedance.com>
✅ Deploy Preview for reactlynx-use ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Pull request overview
This PR introduces a new MTS-oriented hook, useComputedStyle(keys), intended to read resolved computed CSS property values from a main-thread element and bridge them to background-thread React state, enabling patterns like using CSS variables to drive props such as current-color on <svg>.
Changes:
- Added
src/useComputedStyle.tshook and exported it (plusUseComputedStyleReturn) fromsrc/index.ts. - Added English and Chinese documentation for
useComputedStyle, and linked it from the MTS docs READMEs.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/useComputedStyle.ts | Adds the new hook that reads computed styles on the main thread and forwards them to background-thread state. |
| src/index.ts | Exports the new hook and its return type from the package entrypoint. |
| docs/en/mts/useComputedStyle.md | Adds English docs and examples for the new hook. |
| docs/en/mts/README.md | Links the new hook from the English MTS docs index. |
| docs/zh/mts/useComputedStyle.md | Adds Chinese docs and examples for the new hook. |
| docs/zh/mts/README.md | Links the new hook from the Chinese MTS docs index. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| const sendToBackground = runOnBackground( | ||
| (resolved: Record<string, string>) => { | ||
| 'background only'; | ||
| setStyles(resolved); | ||
| }, | ||
| ); |
| * ); | ||
| * ``` | ||
| */ | ||
| export default function useComputedStyle(keys: string[]): UseComputedStyleReturn { |
| ## Limitations | ||
|
|
||
| - The `keys` array is captured by the worklet closure at creation time. If you need to change which properties are read, the component must remount. | ||
| - The resolved values are delivered asynchronously (one main-thread → background-thread round trip), so there may be a single frame where `styles` is empty `{}`. |
| ## 限制 | ||
|
|
||
| - `keys` 数组在 worklet 闭包创建时被捕获。如果需要更改读取的属性,组件必须重新挂载。 | ||
| - 已解析的值是异步传递的(一次主线程 → 后台线程的往返),因此可能存在单帧 `styles` 为空 `{}` 的情况。 |
Add a complete theme-switching example that demonstrates CSS custom properties driving SVG icon colors via the useComputedStyle hook, including both TSX and CSS code with a step-by-step explanation. Co-authored-by: TRAE CLI <traecli@bytedance.com>
Test Results on Android (via lynx-sandbox)✅ Pattern demonstrated: Device: aries_10 (Android, AIC cloud device) Screenshots
Observations
|
Android device test: useComputedStyle working ✓Tested Setup:
Result: Theme switching works correctly. Screenshots — all 4 themes:
How it works (from the demo): // Read computed CSS "color" from main thread:
const [ref, styles] = useComputedStyle(['color']);
const color = styles['color'];
<svg current-color={color} />The Tested on 2026-08-18 via lynx-sandbox device lease. |
Read individual computed properties on MTS after the committed frame, keep the main-thread ref and unchanged results stable, and support explicit invalidation dependencies. Document and verify the CSS custom property to resolved color to SVG current-color chain with real Android screenshots.
|
Authoritative validation update: the older PR comments and screenshots are superseded by this final real-Android run. It exercises the exact same-element |
Report an unresolved property as an absent key instead of an empty string, so a consumer prop keeps whatever behaviour it has when it is not declared. SVG `current-color` falls back to CSS `color` on newer Lynx SDKs, and an explicit empty value suppresses that fallback, so handing out "" would turn a working native fallback into an uncolored icon. - Catch the Lynx SDK < 3.5 throw from getComputedStyleProperty() so it cannot escape into an engine animation frame; warn instead. - Warn when the reader is missing on @lynx-js/react < 0.115.4 rather than resolving nothing silently. - Type styles as Partial<Record<Key, string>> with the requested key literals, so styles[key] is string | undefined and an unrequested key is a type error. - Re-read when `keys` changes, not only when `deps` changes. - Restore the patched element prototype after each test. - Document the fail-open contract, the forward-compatibility rules, and the engine limits tracked in lynx-family/lynx#8682 and #8692.
Review + follow-up commit (c2b1c97)The hook itself was correct after The design question: how does this API keep working?The load-bearing change is a contract: unresolved means absent, never empty.
This matters because element props distinguish absent from empty. SVG Three rules, now documented:
Also fixed
Verification
Not addressed hereOnce SVG falls back to CSS |




Summary
useComputedStyle(keys, deps?)returns a stableMainThreadRefandstyles.Exact verified chain
The real-Android validation exercises this exact end-to-end path:
--theme-coloris set on the same ref view.color: var(--theme-color).requestAnimationFrameand then readsgetComputedStyleProperty("color").current-color.There is no inheritance, no inline
colorsubstitution, no background proxy, and no SVG string replacement.Android validation
Validated on Android with:
engineVersion3.5enableCSSInlineVariablesenable-serval-svgChecks
Documentation and screenshots