ineedtoknow
ineedtoknow

Reputation: 1654

Add Properties to Lit React Wrapper (using @lit/react)

Ok, there's a lit web component I need to use in a React app (which is using TS/TSX).
(In case you think the naming here is odd, I'm using dummy names)

I know I can just have the web component in React like this:

<lit-web-component text="my text"></lit-web-component>

And that works, it displays the component.
However, this lit component also dispatches an event, and I need the React app to catch this.
After researching, I found that I need to use a package(@lit/react) and create a wrapper component to do this. (https://lit.dev/docs/frameworks/react/)

I'm following the documentation, but I keep getting an error with the properties on the lit component (text). It gives this error:

Type '{ text: string; }' is not assignable to type 'IntrinsicAttributes & Omit<HTMLAttributes<HTMLElement>, never> & EventListeners<{}> & Partial<Omit<HTMLElement, keyof HTMLElement>> & RefAttributes<...>'.
  Property 'text' does not exist on type 'IntrinsicAttributes & Omit<HTMLAttributes<HTMLElement>, never> & EventListeners<{}> & Partial<Omit<HTMLElement, keyof HTMLElement>> & RefAttributes<...>

Here is the React wrapper component I'm creating:

export const MyElementComponent = createComponent({
  tagName: 'lit-web-component',
  elementClass: LitWebComponent,
  react: React,
  events: {
    onHeaderButtonClick: 'header-button-click',
  },
});

And then using it in react as: <MyElementComponent text="my text" />

And it produces the above error. I have no idea how to tell it that this wrapper needs to take in these properties.

LitWebComponent is being imported as import { LitWebComponent } from '@my-scope/my-lit-library';

How do I declare these properties?

I hope that this issue is solvable on the React side, making changes to the lit component would be difficult.

Upvotes: 1

Views: 533

Answers (1)

Augustine Kim
Augustine Kim

Reputation: 1186

I'll start off by saying you might not need to use @lit/react for your use case if it's giving you trouble, and props you need to pass in are just strings.

You can use a ref to imperatively add event listeners.

const App = () => {
  const ref = useRef(null);
  
  useEffect(() => {
    if (ref.current) {
      const handler = (e) => { /* do stuff */ }
      ref.current.addEventListener('header-button-click', handler);
      return () => {
        ref.current.removeEventListener('header-button-click', handler);
      }
    }
  });

  return <lit-web-component ref={ref} text="my text"></lit-web-component>;
}

A future version of React (likely 19) will add better custom element support so that you can add event listeners by prepending on to the event name and using that as a prop.

If you still wish to use the @lit/react wrapper,

based on the error, it seems like createComponent is inferring the type of the provided elementClass to be HTMLElement, when it should be the class extending HTMLElement, LitWebComponent which should also have the text property.

@lit/react exports a ReactWebComponent type which you could try and use it like

import {createComponent, type ReactWebComponent} from '@lit/react';

const _MyElementComponent = createComponent({
  tagName: 'lit-web-component',
  elementClass: LitWebComponent,
  react: React,
  events: {
    onHeaderButtonClick: 'header-button-click',
  },
});

export const MyElementComponent =
  _MyElementComponent as ReactWebComponent<
    LitWebComponent, {onHeaderButtonClick: 'header-button-click'}
  >;

though if the type inference didn't work, I'm not sure that would work.

You can also assert the type more directly like

interface ElementProps {
  text: string;
  onHeaderButtonClick: (e: Event) => void;
}

export const MyElementComponent =
  _MyElementComponent as React.ForwardRefExoticComponent<
    React.PropsWithoutRef<ElementProps> & React.RefAttributes<LitWebComponent>
  >

Upvotes: 0

Related Questions