Search code examples
web-componentstenciljsstencil-component

Using jQuery and bootstrap JS with stenciljs components


We have application that is built using Angular and now for all customer-specific requirements we want to build web components using stencil js.

Idea is to keep core application clean and not to mixin code for specific client requirements.

So we came up to web components and we stick to Stencil JS.

First problem that we are facing is that our web component will need to use jquery, bootstrap js and some third party js as well.

We want to build our components to be encapsulated from outside that means they will be in shadow dom.

Now I have two questions

1) Is it good practice that every component include JS libraries like jQuery, bootstrap js etc because it doesn't sound to me as a good idea 2) How we can include jQuery for example into web component.

I tried many ways and the last one was to include tag in the constructor of a stencil web component, but it doesn't work.

export class TestComponent {

  @Prop() token: string;

  @State() test: string;
  @Element() private element: HTMLElement;

  constructor() {

    this.element.innerHTML = `
    <script src="../../assets/js/jquery.min.js"></script>

`;

So the question is how to use JS third party libraries in web component built in stencil that is in shadow dom ( shadow option is set to true )

Any opinions about this in general are welcome and will be appreciated :)


Solution

  • For me it sounds like you are bending the purpose of Stencil and Web-components a bit. I never had this pain doing this but to answer your question: It depends of what you wanna achieve. For example you can use Jquery natively inside the shadow-dom when you import Jquery in the Light-dom.

    Index.html

    <script src="/jquery.min.js"></script>
    </head>
    <body>
      <my-component></my-component>
      <div id="test2"></div>
    </body>
    

    my-component.tsx

      testfunc(){
        console.log($().jquery);
        console.log($("#test"));
        console.log($("#test2"));
      }
      render() {
        return <div id="test">
                <button onclick={this.testfunc.bind(this)}>asd</button>
               </div>;
      }
    

    The result of testfunc are here: Console results:

    So as you can see - you already can use Jquery just by putting it into your main application. But there are some limitations as you can see you have access to all the DOM elements from light-dom but none from shadow-dom. Thats why #test wasn't found and #test2 was.

    But interesting to mention here is that I was also able to load a file inside this #test2 div container which is in the index.html. Just by using the jquery .load function from inside the web-component.

    $( "#test2" ).load( "/index.html" );
    

    Things get a bit more complicated when you want to use the $ selector to get elements inside the web-component (shadow-dom) but there is absolutely no reason to do so: Stencil has it's own this.el.shadowRoot.querySelector() that you can use inside the component or you can directly stick a variable to a DOM element like so:

      render() {
        return <div ref={el => this.element = el}>
                <button onclick={this.testfunc.bind(this)}>Press Button</button>
               </div>;
      }
    

    Than you can use this.element inside the web-component to access the div. But in general you can also try to use the scoped flag in the component decorator. Than you usually can use everything from the light dom because there is not such a hard isolation:

        @Component({
      tag: 'my-component',
      styleUrl: 'my-component.css',
      shadow: true ---> instead of this
      scoped: true ---> try this
    })
    

    To summarize a bit: I think there is never a good reason to use these libraries inside a web-component in general. But if you really have to - it always depends on your needs and what you want / need to achieve. Stencil has some really helpful and good built in functions.