Skip to content

feat(lit): support universal web components in v0.9 renderer - #2311

Draft
josemontespg wants to merge 1 commit into
lit-create-component-implementationfrom
lit-universal-components
Draft

feat(lit): support universal web components in v0.9 renderer#2311
josemontespg wants to merge 1 commit into
lit-create-component-implementationfrom
lit-universal-components

Conversation

@josemontespg

@josemontespg josemontespg commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR adds support for universal web components in the @a2ui/lit v0.9 renderer, matching the architecture and design established in Angular (#2273) and React (#2283).

Key Changes:

  • Catalogs & Extensibility:
    • Added BasicCatalogOptions interface supporting catalog ID, locale, component overrides (components), extra components (extraComponents), custom functions (functions), and the useUniversalComponents toggle.
    • Added NativeBasicCatalog, UniversalBasicCatalog, and BasicCatalog classes.
    • Added canonical collections BASIC_COMPONENTS, BASIC_NATIVE_COMPONENTS, BASIC_UNIVERSAL_COMPONENTS, and BASIC_FUNCTIONS.
    • Re-exported all individual basic component APIs and function helpers from the basic catalog.
  • Custom Element Adapter:
    • Implemented toWebComponent adapter to convert custom Lit element classes or render functions ((context) => TemplateResult) into standard WebComponentImplementation custom element definitions.
    • Added createComponentImplementation helper for constructing component implementations.
  • Surface Rendering & Dynamic Node Resolution:
    • Updated renderA2uiNode in Lit surface rendering to accept Catalog<LitComponentApi> and dynamically resolve and mount custom web components into Light DOM.
  • Explorer & Sample Clients:
    • Updated Lit explorer gallery and Lit sample client shell to support useUniversalComponents via query parameter.
  • Tests & Verification:
    • Added comprehensive test suite universal-components.test.ts verifying catalog instantiation, component overrides, extra components, locale functions, toWebComponent caching/idempotency, and end-to-end surface rendering.
    • Updated basic-catalog-a2ui-lit-element.test.ts to verify light DOM, styling, flex weight, and theme color behavior.
  • Documentation:
    • Added changelog entry in renderers/lit/CHANGELOG.md.

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • My PR includes tests for new or changed code.
  • My PR title respects the semantic release format.
  • I updated CHANGELOG.md with notes describing my changes.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for Universal Web Components in the Lit renderer, adding BasicCatalog, NativeBasicCatalog, UniversalBasicCatalog, and a toWebComponent adapter. The review feedback focuses on simplifying component catalog instantiation and avoiding redundant or duplicated checks. Specifically, the reviewer suggests updating toWebComponent to return existing WebComponentImplementation objects directly (with defensive checks), which allows simplifying component overrides and extra component handling in UniversalBasicCatalog. Additionally, suggestions were made to simplify the NativeBasicCatalog constructor and align the getUseUniversalComponents helper in the shell app with the explorer's implementation for consistency.

Comment thread samples/client/lit/shell/app.ts Outdated
Comment on lines +39 to +46
function getUseUniversalComponents(): boolean {
if (typeof window !== 'undefined' && window.location) {
const params = new URLSearchParams(window.location.search);
const val = params.get('useUniversalComponents');
return val === 'true' || val === '1';
}
return false;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The getUseUniversalComponents helper in the shell app defaults to true and checks both useUniversalComponent and useUniversalComponents to match the explorer's implementation, ensuring consistent behavior across both environments.

Suggested change
function getUseUniversalComponents(): boolean {
if (typeof window !== 'undefined' && window.location) {
const params = new URLSearchParams(window.location.search);
const val = params.get('useUniversalComponents');
return val === 'true' || val === '1';
}
return false;
}
function getUseUniversalComponents(): boolean {
if (typeof window === 'undefined') return true;
const params = new URLSearchParams(window.location.search);
const param = params.get('useUniversalComponent') || params.get('useUniversalComponents');
if (param !== null) {
return param.toLowerCase() === 'true' || param === '1';
}
return true;
}

Comment on lines +150 to +155
const baseComponents = new Map<string, LitComponentApi>(
Object.entries(DEFAULT_NATIVE_COMPONENT_IMPLEMENTATIONS).map(([key, impl]) => [
impl.name || key,
impl,
]),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The keys of DEFAULT_NATIVE_COMPONENT_IMPLEMENTATIONS are already mapped to impl.name || key. Mapping them again in the NativeBasicCatalog constructor is redundant. You can pass Object.entries(DEFAULT_NATIVE_COMPONENT_IMPLEMENTATIONS) directly to the Map constructor.

    const baseComponents = new Map<string, LitComponentApi>(
      Object.entries(DEFAULT_NATIVE_COMPONENT_IMPLEMENTATIONS)
    );

Comment on lines +195 to +204
if (options.components) {
for (const [key, comp] of Object.entries(options.components)) {
if (comp) {
let resolvedComp =
'tagName' in comp &&
typeof comp.tagName === 'string' &&
!('element' in comp) &&
!('render' in comp)
? comp
: toWebComponent(comp);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This complex check to determine if a component is already a WebComponentImplementation is duplicated multiple times in this file and in toWebComponent. By updating toWebComponent to return the component directly if it is already a WebComponentImplementation, we can simplify this logic and avoid duplication.

Suggested change
if (options.components) {
for (const [key, comp] of Object.entries(options.components)) {
if (comp) {
let resolvedComp =
'tagName' in comp &&
typeof comp.tagName === 'string' &&
!('element' in comp) &&
!('render' in comp)
? comp
: toWebComponent(comp);
if (options.components) {
for (const [key, comp] of Object.entries(options.components)) {
if (comp) {
let resolvedComp = toWebComponent(comp);

Comment on lines +216 to +226
const extra = (options.extraComponents ?? []).map(comp => {
if (
'tagName' in comp &&
typeof comp.tagName === 'string' &&
!('element' in comp) &&
!('render' in comp)
) {
return comp;
}
return toWebComponent(comp);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the components override, this duplicated check can be entirely avoided by relying on toWebComponent directly, provided toWebComponent is updated to return the component directly if it is already a WebComponentImplementation.

    const extra = (options.extraComponents ?? []).map(comp => toWebComponent(comp));

Comment thread renderers/lit/src/v0_9/catalogs/to_web_component.ts Outdated
@josemontespg
josemontespg force-pushed the lit-universal-components branch 7 times, most recently from e08e39b to c6ee897 Compare August 18, 2026 00:00
@josemontespg
josemontespg changed the base branch from react-universal-components to lit-create-component-implementation August 18, 2026 00:01
@josemontespg
josemontespg force-pushed the lit-universal-components branch from c6ee897 to b61f60b Compare August 18, 2026 00:11
@josemontespg
josemontespg force-pushed the lit-universal-components branch from b61f60b to cc371ac Compare August 18, 2026 00:28
@josemontespg
josemontespg force-pushed the lit-universal-components branch from cc371ac to 10069d4 Compare August 18, 2026 00:40
Comment thread renderers/lit/src/v0_9/catalogs/to_web_component.ts Outdated
});
});

describe('toWebComponent Adapter', () => {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move these tests to their own file next to the implementation file.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved toWebComponent tests into renderers/lit/src/v0_9/catalogs/to_web_component.test.ts next to the implementation file.


after(teardownTestDom);

describe('Basic Catalog Re-export', () => {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this test. It is not super useful

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the basic catalog re-export test.

@josemontespg
josemontespg force-pushed the lit-universal-components branch 3 times, most recently from c237788 to abbad7a Compare August 18, 2026 01:05
Comment thread renderers/lit/src/v0_9/types.ts Outdated
* Interface representing a Lit or Web Component implementation.
*/
export type LitComponentImplementation<Schema extends ZodTypeAny = ZodTypeAny> =
WebComponentImplementation<Schema>;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not necessary. Remove.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed LitComponentImplementation.

Comment thread renderers/lit/src/v0_9/types.ts Outdated
*/
export type LitComponentApi = WebComponentImplementation;
export type LitComponentApi<Schema extends ZodTypeAny = ZodTypeAny> =
WebComponentImplementation<Schema>;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed. Remove.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted LitComponentApi back to export type LitComponentApi = WebComponentImplementation;.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted formatting script changes in samples/client/lit/shell/package.json.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this test file

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed universal-components.test.ts.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this test need to change so much?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In PR #2190, BasicCatalogA2uiLitElement and its test suite were migrated to renderers/web_core/src/v0_9/basic_catalog/. This test file in renderers/lit was a redundant legacy copy testing old internal class properties, so it has been removed.

@josemontespg
josemontespg force-pushed the lit-universal-components branch from abbad7a to 8b73fd9 Compare August 18, 2026 01:13
@josemontespg
josemontespg force-pushed the lit-universal-components branch 6 times, most recently from 27b0817 to 1613e57 Compare August 18, 2026 20:13
@josemontespg
josemontespg force-pushed the lit-universal-components branch from 1613e57 to 038f77e Compare August 18, 2026 20:30
@josemontespg
josemontespg force-pushed the lit-universal-components branch from 038f77e to d3f10fa Compare August 18, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant