How to use Custom Elements with a Framework
drab can be utilized in any framework that supports custom elements.
TypeScript support
If you are using TypeScript, drab includes types for each attribute of each element so you can get autocomplete and type safety just like you would from a framework component. Add a d.ts
file within your tsconfig.include
paths to extend the types of your framework’s intrinsic elements (examples below).
Server rendering
drab is built to be compatible with server-side rendering (SSR). If you are using SSR, you will need to ensure the element’s code only runs on the client. Below are examples on how to do this in popular JavaScript frameworks with functions like onMount
or useEffect
. If you aren’t using SSR, you can omit these wrappers since the code will only run on the client.
Examples
*If you see a better way to write any of these examples or a framework that is missing, please create an issue or pull request!
Astro
---
// dialog.astro
import type { DialogAttributes } from "drab/dialog";
const attributes: DialogAttributes = {
// ...
};
---
<script>
import "drab/dialog/define";
</script>
<drab-dialog {...attributes}>...</drab-dialog>
Enhance
// app/elements/my-dialog.mjs
export default function MyDialog({ html }) {
return html`
<drab-dialog>...</drab-dialog>
<script src="/_public/browser/drab-dialog.mjs" type="module"></script>
`;
}
// app/browser/drab-dialog.mjs
import "drab/dialog/define";
React
"use client";
// dialog.tsx
import { useEffect } from "react";
export default function Dialog() {
useEffect(() => {
import("drab/dialog/define");
}, []);
return <drab-dialog>...</drab-dialog>;
}
// drab.d.ts
import type { Elements } from "drab/types";
import type { HTMLAttributes } from "react";
declare module "react" {
namespace JSX {
interface IntrinsicElements extends Elements<HTMLAttributes<HTMLElement>> {}
}
}
Solid
// dialog.tsx
import { onMount } from "solid-js";
export default function Dialog() {
onMount(() => {
import("drab/dialog/define");
});
return <drab-dialog>...</drab-dialog>;
}
// drab.d.ts
import type { Elements } from "drab/types";
import "solid-js";
declare module "solid-js" {
namespace JSX {
interface IntrinsicElements
extends Elements<JSX.HTMLAttributes<HTMLElement>> {}
}
}
Svelte
<!-- dialog.svelte -->
<script lang="ts">
import { onMount } from "svelte";
onMount(() => {
import("drab/dialog/define");
});
</script>
<drab-dialog>...</drab-dialog>
// drab.d.ts
import type { Elements } from "drab/types";
declare module "svelte/elements" {
export interface SvelteHTMLElements
extends Elements<HTMLAttributes<HTMLElement>> {}
}
export {};
Vue
<!-- dialog.vue -->
<script setup>
onMounted(() => {
import("drab/dialog/define");
});
</script>
<template>
<drab-dialog>...</drab-dialog>
</template>
// nuxt.config.ts
export default defineNuxtConfig({
vue: { compilerOptions: { isCustomElement: (tag) => tag.includes("-") } },
});