Add Example of How to Use Custom Elements in Fresh
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:
- Creating a custom component file.
- Importing and using the custom component in a Fresh route.
- Best practices for organizing custom components within a Fresh project.
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.
Steps to Use a Custom Component in a Fresh Project
-
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>
-
Deploy the Component
- Deploy
my-component.htmlto a static hosting service (e.g., GitHub Pages, deno deploy). - Example URL:
https://yourusername.github.io/my-component.html.
- Deploy
-
Declare the Component in TypeScript
- Add the component to the
IntrinsicElementsinterface in yourglobal.d.tsxfile.
- Add the component to the
// types/global.d.tsx
declare module "preact" {
namespace JSX {
interface IntrinsicElements {
"my-component": {
flag?: string;
label?: string;
children?: preact.ComponentChildren;
slot?: string;
};
}
}
}
-
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.
Oh I see, you are interested in using custom elements in fresh.
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
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
@marvinhagemeister We are using native web components in a Fresh project as follows:
- 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);
- 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>
- 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 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.
https://github.com/preactjs/preact-custom-element
this repo may help for
How to use web components or other custom content?