DEV Community

Gil Fink
Gil Fink

Posted on • Originally published at gilfink.Medium on

Writing Your First Qwik Component

In the last few weeks I’m deep diving into Qwik framework in preparation to a session I’ll deliver about it in TechRadarCon 2022. I also implemented a full demo app with Qwik and QwikCity to get the feeling about the developer experience with the framework.

In this post I’m going to show you how you can develop a simple Qwik component and expose you to some things you need to know while developing your components.

Qwik Playground


Qwik Playground

One of the nice features that is part of Qwik website is the Qwik Playground. In the playground you can write components using Qwik syntax and in the right pane you can get info about the component’s rendering, errors, symbols and can even configure how things are rendered using the Options tab at the bottom.

You can use the playground as the environment to build the component I’ll implement in the post or you can create a new project using Qwik CLI and add the component there.

Building the Component

In this post we are going to build a simple collapsible panel component. The component will have a clickable header, which will collapse it’s content. The content will be injected from the outside.

So, let’s do it :)

The following code is the complete example, which will be broken to explanations later on:

import { component$, useStore, useStylesScoped$, $, Slot } from '@builder.io/qwik';

export const App = component$(() => {
  return (
    <CollapsiblePanel title="Click me!">
      <ul>
        <li>Qwik is awsome</li>
        <li>Collapsible item</li>
      </ul>
    </CollapsiblePanel>
  );
});

interface IProps {
  title: string;
}

export const CollapsiblePanel = component$(({ title }: IProps) => {
  useStylesScoped$(`
    .collapsible {
      border: black dashed 1px;
    }

header {
      background: blue;
      color: white;
      cursor: pointer;
      padding: 2px;
    }
  `);

const store = useStore({
    collapsed: false
  });

const toggle = $(async () => {
    store.collapsed = !store.collapsed;
  });

return (
    <div className="collapsible">
        <header onClick$={toggle}>
          {title}
        </header>
        <section hidden={store.collapsed}>
          <Slot />
        </section>
      </div>
  );
});
Enter fullscreen mode Exit fullscreen mode

Let’s Break it Down

Qwik embraces TypeScript, so at first we will create an interface for the props that the component will receive. Here is the interface implementation:

interface IProps {
  title: string;
}
Enter fullscreen mode Exit fullscreen mode

Now that we have the interface, let’s use it and let’s declare the component using Qwik syntax:

export const CollapsiblePanel = component$(({ title }: IProps) => {
   ...
});
Enter fullscreen mode Exit fullscreen mode

As you can see you use the component$ function to create a Qwik component. The $ sign is there to direct Qwik optimizer to treat this function in a specific way (in this case, as a Qwik component).

Note: I’m not going to discuss the optimizer and I encourage you to read about it here.

Now that we declared the component let’s implement it. Qwik uses JSX to write how you will render your component. At the end of the component we will return the following JSX:

return (
    <div className="collapsible">
        <header onClick$={toggle}>
          {title}
        </header>
        <section hidden={store.collapsed}>
          <Slot/>
        </section>
     </div>
);
Enter fullscreen mode Exit fullscreen mode

As can be seen, we return a div with some implementation. I marked 3 important things in the code which you should be aware of. The onClick$ is the way we wire events in Qwik with the $ sign at the end. Again, the $ sign is there for the Qwik optimizer. The Slot component is a special Qwik component that enables content injection into our component. We will discuss the store later on.

Now let’s add some style. If you want to create a style barrier between your component and the outside you can use the useStylesScoped$ hook. The useStylesScoped$ hook receives the style you want to encapsulate inside your component and impose it on the component.

useStylesScoped$(`
    .collapsible {
      border: black dashed 1px;
    }

    header {
      background: blue;
      color: white;
      cursor: pointer;
      padding: 2px;
    }
`);
Enter fullscreen mode Exit fullscreen mode

In the example above we add style to the container div and to the header element. When rendered, Qwik will make sure that the style will be specific only to the component and therefore the style won’t leak from it.

In order to have an inner component state, which can be serialized by Qwik you will need to use the useStore hook. The hook creates a store that it’s content can be tracked by Qwik and also can be serialized. In the collapsible panel example the store is storing the collapsed state of the component:

const store = useStore({
    collapsed: false
});
Enter fullscreen mode Exit fullscreen mode

Last but not least, we implement the toggle function which will be used to toggle the content:

const toggle = $(async () => {
    store.collapsed = !store.collapsed;
});
Enter fullscreen mode Exit fullscreen mode

Since the toggle function isn’t inline in the component’s JSX, you need to use the $(async () => { … }) syntax to make sure that Qwik optimizer will understand that this is going to be Qwik component function that is being used in the JSX.

That is it. You now can play with the component.

The following code is a consuming component that runs our component:

export const App = component$(() => {
  return (
    <CollapsiblePanel title="Click me!">
      <ul>
        <li>Qwik is awsome</li>
        <li>Collapsible item</li>
      </ul>
    </CollapsiblePanel>
  );
});
Enter fullscreen mode Exit fullscreen mode


The Collapsible Panel Component in Qwik Playground

Summary

In the post we implemented a Qwik collapsible panel component. This is a simple component but it shows some of the concepts you will need to be familiar with if you are writing Qwik components.

As always, if you have any feedback, let me know.

Top comments (0)