fresh icon indicating copy to clipboard operation
fresh copied to clipboard

Add Example of How to Use Custom Elements in Fresh

Open dhruv-dabhi-st7 opened this issue 1 year ago • 8 comments

Description Currently, the Deno Fresh documentation lacks an example of how to integrate and use a custom-created component that is not built into the Deno stack. This can be challenging for developers who want to extend their Fresh applications with custom components.

Proposed Solution: Add a section in the documentation that provides a step-by-step guide on how to create and use a custom component in a Fresh project. The example should include:

  1. Creating a custom component file.
  2. Importing and using the custom component in a Fresh route.
  3. Best practices for organizing custom components within a Fresh project.

dhruv-dabhi-st7 avatar Oct 29 '24 03:10 dhruv-dabhi-st7

What is a "custom component"? Do you mean a Preact component? If yes, then it looks like this:

function MyComponent() {
  return <h1>hello world</h1>
}

// usage
<MyComponent />

But not sure if this is what you're asking.

marvinhagemeister avatar Oct 29 '24 08:10 marvinhagemeister

Steps to Use a Custom Component in a Fresh Project

  1. Create the Component
    • Write your component in HTML, CSS, and JavaScript.
    • Example: my-component.html.
<!-- my-component.html -->
<template id="my-component-template">
  <style>
    /* Add your CSS here */
    .my-component {
      color: red;
    }
  </style>
  <div class="my-component">
    <!-- Add your HTML here -->
    <p>Hello, I am a custom component!</p>
  </div>
</template>

<script>
  class MyComponent extends HTMLElement {
    constructor() {
      super();
      const template = document.getElementById('my-component-template').content;
      this.attachShadow({ mode: 'open' }).appendChild(template.cloneNode(true));
    }
  }

  customElements.define('my-component', MyComponent);
</script>
  1. Deploy the Component

    • Deploy my-component.html to a static hosting service (e.g., GitHub Pages, deno deploy).
    • Example URL: https://yourusername.github.io/my-component.html.
  2. Declare the Component in TypeScript

    • Add the component to the IntrinsicElements interface in your global.d.tsx file.
// types/global.d.tsx
declare module "preact" {
  namespace JSX {
    interface IntrinsicElements {
      "my-component": {
        flag?: string;
        label?: string;
        children?: preact.ComponentChildren;
        slot?: string;
      };
    }
  }
}
  1. Usage in Fresh
    • Include the script for your custom component in your HTML.
    • Use the component in your Fresh project with proper TypeScript declarations.
// routes/index.tsx
export default function Home() {
  return (
    <>
      <my-component flag="example"></my-component>
    </>
  );
}

This setup allows you to create, deploy, and use a custom component in a Fresh project.

dhruv-dabhi-st7 avatar Oct 30 '24 03:10 dhruv-dabhi-st7

Oh I see, you are interested in using custom elements in fresh.

marvinhagemeister avatar Oct 30 '24 06:10 marvinhagemeister

Oh I see, you are interested in using custom elements in fresh.

Yes so for that i suggest to add a section in the documentation that provides a step-by-step guide on how to create and use a custom elements as a component in a Fresh project

dhruv-dabhi-st7 avatar Oct 30 '24 10:10 dhruv-dabhi-st7

Hello, I have the same interest. Today I use Astro with Custom Elements, but I have appreciation for Deno Fresh, so I would like to use it, but using Custom Elements. Thanks

falvarador avatar Oct 31 '24 15:10 falvarador

@marvinhagemeister We are using native web components in a Fresh project as follows:

  1. Create a web component:

Create a file named button.js inside the static/components directory:

// static/components/button.js
const ButtonComponent = class extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: "open" });
  }

  connectedCallback() {
    this.render();
    this.addEventListener("click", this.handleClick);
  }

  disconnectedCallback() {
    this.removeEventListener("click", this.handleClick);
  }

  handleClick() {
    // Add your click handler logic here
  }

  render() {
    this.shadowRoot.innerHTML = `
      <style>
        /* Add your button styles here */
      </style>
      <button>
        <slot></slot>  </button>
    `;
  }
};

customElements.define("button-component", ButtonComponent);
  1. Import the web component:

Add the following <script> tag within the <head> of routes/_app.tsx

<head>
  <script type="module" src="./components/button.js"></script>
  ...
</head>
  1. Use the web component:

Use the component in Fresh components (e.g., routes/index.tsx or any other JSX/TSX file):

// routes/index.tsx
export default function Home() {
  return (
    <>
      <button-component>Click me</button-component>
       <button-component>Another Button</button-component>
    </>
  );
}

Is this approach fine, or are there better solutions in Fresh for using web components?

beingminimal avatar Feb 18 '25 08:02 beingminimal

@beingminimal the approach in your comment is not SSR friendly. And can probably cause FOUC.

There is a declarative shadow root now.... I am just not sure how it plays with frameworks

<my-component>
<template shadowrootmode="open">
  <style>
    /* Add your CSS here */
    .my-component {
      color: red;
    }
  </style>
  <div class="my-component">
    <!-- Add your HTML here -->
    <p>Hello, I am a custom component!</p>
  </div>
</template>
</ my-component>

<script>
  class MyComponent extends HTMLElement {
// no need when using declarative shadow DOM
//    constructor() {
//      super();
//      const template = document.getElementById('my-component-template').content;
//      this.attachShadow({ mode: 'open' }).appendChild(template.cloneNode(true));
//    }
  }

  customElements.define('my-component', MyComponent);
</script>

Please see https://web.dev/articles/declarative-shadow-dom

I am also pretty interested to see how Web Components play along with Fresh.

predragnikolic avatar Feb 19 '25 11:02 predragnikolic

https://github.com/preactjs/preact-custom-element

this repo may help for

SisyphusZheng avatar May 22 '25 18:05 SisyphusZheng

How to use web components or other custom content?

zhang-wenchao avatar Jul 08 '25 07:07 zhang-wenchao