Components usage

Browser support

We support only modern browsers.

npx browserslist "> 1%, last 2 versions, not dead, not ie 11"

So it doesn't run on legacy browsers: IE11, Edge 18 & below (Edge before it moved to Chromium), and Safari 10.

Usage with basic HTML

The easiest way to install Graphite components is with the CDN. A lightweight loader will be added to your page that registers components asynchronously as you use them. It's like magic. ✨

The CDN is optimized for performance by using caching, HTTP/2, etc.

Just add the following tags to the head of your page.

<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@graphiteds/core@1.9.5/css/graphite.bundle.css"
integrity="sha256-gFHf9tmgozxinafVf1kRA43fM6cmXpQecxRncZdH3NI="
crossorigin="anonymous"
/>

<script
type="module"
src="https://cdn.jsdelivr.net/npm/@graphiteds/core@1.9.5/dist/core/core.esm.js"
integrity="sha256-X596KR2pkHnXVlgT0v2btsGxOW0eUVIPb8mcQnfiRko="
crossorigin="anonymous"
>
</script>

Then you can use the elements anywhere in your template, JSX, html etc.

For example:

<gr-button href="https://paqt.com">PAQT</gr-button>

Note: All components are only lazy-loaded by the browser when needed. This can introduce some Cumulative Layout Shift (CLS). To reduce this, you can move the components below the fold (outside the visible viewport of the user, or use a bundler with cherry-picked components.

See a working example of this setup (CodeSandbox)

Usage with bundlers

Follow these instructions if you use a bundler such as webpack, vite, or rollup (specific instructions for Vue, React, and Angular are documented further on).

Self lazy-loading components

Run:

npm install @graphiteds/core

Add this code to your main JS/TS file:

// Import Graphite components
import { defineCustomElements } from '@graphiteds/core/loader';

// Core CSS required for Graphite components to work properly
import '@graphiteds/core/css/core.css';

// Optional CSS to prevent Flash Of Unstyled Content (FOUC) because of the lazy loading
import '@graphiteds/core/css/prevent-fouc.css';

// Register Graphite components
defineCustomElements(window);

Note: All components are part of your bundle, but only lazy-loaded by the browser when needed. This can introduce some Cumulative Layout Shift (CLS). Alternately, cherry-pick components for optimal bundle size, and to reduce Cumulative Layout Shift (CLS). Or if you want to use some other bundler than webpack (because of this issue).

Cherry-pick components

Run:

npm install @graphiteds/core

Add this code to your main JS/TS file:

// Core CSS required for Graphite components to work properly
import '@graphiteds/core/css/core.css';

Add code like this to the files where you want to use the components, depending on the components you use:

// Import & register gr-button component
import '@graphiteds/core/components/gr-button.js';

This automatically defines the custom element, and imports any components it depends upon.

This enables the bundler to remove unused Graphite components from your bundle (tree-shaking). If you use Webpack, we recommend to use Webpack 5 to make the most out of this improvement.

Usage with Vue 3

We offer Vue 3 wrappers on top of @graphiteds/core components for optimal DX (typings, v-model support, out of the box tree-shaking, etc.).

We recommend using vite or otherwise vue-cli v5 (with Webpack 5) for the best bundle sizes (due to tree-shaking). If you want to migrate from vue-cli v4 to v5: follow this guide.

Run:

npm install @graphiteds/vue

Edit the main.js or main.ts file of a Vue 3 project like this:

import { createApp } from 'vue';
import App from './App.vue';
import { GraphiteVue } from '@graphiteds/vue';

// Core CSS required for Graphite components to work properly
import '@graphiteds/vue/css/core.css';

createApp(App).use(GraphiteVue).mount('#app');

Import the component(s) you want to use:

import { GrButton } from '@graphiteds/vue';

Use it in your template as any Vue component:

// In kebab-case
<gr-button href="https://paqt.com">PAQT</gr-button>

// Or PascalCase
<GrButton href="https://paqt.com">PAQT</GrButton>

We recommend using kebab-case for our components and PascalCase for your own Vue components to make them visible distinct.

See a working example of this setup (CodeSandbox) using vue-cli v4

VSCode with Vetur and this setting:

"vetur.experimental.templateInterpolationService": true

Or WebStorm.

Usage with Vue 2

If you use Vue with a direct script include, look at this example to get up and running quickly.

Otherwise when using a bundler, follow these steps:

Run:

npm install @graphiteds/core

Edit the main.js or main.ts file of a Vue 2 project to include:

// Import Graphite components
import { defineCustomElements } from '@graphiteds/core/loader';

// Core CSS required for Graphite components to work properly
import '@graphiteds/core/css/core.css';

// Optional CSS to prevent Flash Of Unstyled Content (FOUC) because of the lazy loading
import '@graphiteds/core/css/prevent-fouc.css';

// ...

// configure Vue.js to ignore Graphite components
Vue.config.ignoredElements = [/gr-\w*/];

// Register Graphite components
defineCustomElements(window);

new Vue({
render: (h) => h(App),
}).$mount('#app');

The components should then be available in any of the Vue components:

<template>
<gr-button href="https://paqt.com">PAQT</gr-button>
</template>

Vue provides several different ways to install and use the framework in an application. The above technique has been tested on a Vue 2 application that was created using the vue-cli. A similar technique should work if the application was generated using other options.

See a working example of this setup (CodeSandbox)

Note: All components are part of your bundle, but only lazy-loaded by the browser when needed. Alternately, cherry-pick components for optimal bundle size. Or if you use some other bundler than webpack (because of this issue).

Note: All components are part of your bundle, but only lazy-loaded by the browser when needed. This can introduce some Cumulative Layout Shift (CLS). Alternately, cherry-pick components for optimal bundle size, and to reduce Cumulative Layout Shift (CLS). Or if you want to use some other bundler than webpack (because of this issue).

Binding Complex Data

When binding complex data such as objects and arrays, use the .prop modifier to make Vue bind them as a property instead of an attribute:

<gr-example :options.prop="myOptions"></gr-example>

Note: currently we have no props in our components that need this.

Two-way Binding

One caveat is there's no support for v-model on custom elements in Vue 2, but you can still achieve two-way binding manually:

<!-- This doesn't work -->
<gr-input v-model="name"></gr-input>

<!-- This works, but it's a bit longer -->
<gr-input :value="name" @gr-change="name = $event.target.value"></gr-input>

If that's too verbose, you can use a custom directive instead.

Using a Custom Directive

You can use this utility to add a custom directive to Vue that will work just like v-model but for Graphite components. To install it, use this command.

npm install @graphiteds/vue2-gr-model

Next, import the directive and enable it like this.

import GraphiteModelDirective from '@graphiteds/vue2-gr-model';

Vue.config.ignoredElements = [/^gr-/];
Vue.use(GraphiteModelDirective);

// Your init here
new Vue({ ... });

Now you can use the v-gr-model directive to keep your data in sync!

<gr-input v-gr-model="name"></gr-input>

Usage with Nuxt 2

Run:

npm install @graphiteds/core

Edit nuxt.config.js to include:

module.exports = {
vue: {
config: {
ignoredElements: [/gr-\w*/],
},
},
};

Add plugins/graphiteds.js with the following content:

// Import Graphite components
import { defineCustomElements } from '@graphiteds/core/loader';

// Core CSS required for Graphite components to work properly
import '@graphiteds/core/css/core.css';

// Optional CSS to prevent Flash Of Unstyled Content (FOUC) because of the lazy loading
import '@graphiteds/core/css/prevent-fouc.css';

export default function () {
if (process.client) {
defineCustomElements(window);
}
}

Add the plugin to the project configuration (nuxt.config.js):

module.exports = {
plugins: ['~/plugins/graphiteds.js'],
};

The components should then be available in any of the Nuxt pages & components:

<template>
<gr-button href="https://paqt.com">PAQT</gr-button>
</template>

The instructions above about Binding Complex Data, Two-way Binding, and Using a Custom Directive also apply here (except you need to do the Vue.use(GraphiteModelDirective) in the graphiteds.js plugin).

Note: All components are part of your bundle, but only lazy-loaded by the browser when needed. This can introduce some Cumulative Layout Shift (CLS). Alternately, cherry-pick components for optimal bundle size, and to reduce Cumulative Layout Shift (CLS). Or if you want to use some other bundler than webpack (because of this issue).

See a working example of this setup (CodeSandbox)

Usage with React

We offer React wrappers on top of @graphiteds/core components, because React does not play nice with custom elements, and to offer optimal DX (typings, out of the box tree-shaking, etc.).

Run:

npm install @graphiteds/react

In your index.js or index.ts add the following code:

// Core CSS required for Graphite components to work properly
import '@graphiteds/react/css/core.css';

Import the component(s) you want to use:

import { GrButton } from '@graphiteds/react';

Use it in your JSX as any React component:

<GrButton href="https://paqt.com">PAQT</GrButton>

See a working example of this setup (CodeSandbox)

Usage with Angular

Angular wrappers are possible for optimal DX (typings, ngModel & reactive forms support, etc.). Please let us know if you would like them, and we will consider them.

Otherwise, to use our web components directly within an Angular CLI project, run:

npm install @graphiteds/core

Include CUSTOM_ELEMENTS_SCHEMA in any module that uses our components. This allows the use of the web components in the HTML markup without the compiler producing errors. This code should be added into the AppModule and in every other modules that uses our components. Here is an example of adding it to AppModule:

// ...
// Import custom elements schema
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';

@NgModule({
// ...
// Add custom elements schema to NgModule
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}

The final step is to load and register the Graphite components in the browser. @graphiteds/core includes a main function that handles this. That function is called defineCustomElements() and it needs to be called once during the bootstrapping of your application. One convenient place to do this is in main.ts as such:

// Import Graphite components
import { defineCustomElements } from '@graphiteds/core/loader';

// Core CSS required for Graphite components to work properly
import '@graphiteds/core/css/core.css';

// Optional CSS to prevent Flash Of Unstyled Content (FOUC) because of the lazy loading
import '@graphiteds/core/css/prevent-fouc.css';

// ...

// Register Graphite components
defineCustomElements(window);

Once included, components can be used in your HTML markup as in the following example:

<gr-button variant="primary">Send</gr-button>

Note: All components are part of your bundle, but only lazy-loaded by the browser when needed. This can introduce some Cumulative Layout Shift (CLS). Alternately, cherry-pick components for optimal bundle size, and to reduce Cumulative Layout Shift (CLS). Or if you want to use some other bundler than webpack (because of this issue).

See a working example of this setup (CodeSandbox)

Usage with Livewire

Just add the following tags to the head of your page.

<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@graphiteds/core@1.8.1/css/graphite.bundle.css"
integrity="sha256-Maq0H86dB7RsnWif+qVcjQTCDWf91cqcF+kokcsZ8m0="
crossorigin="anonymous"
/>

<script
type="module"
src="https://cdn.jsdelivr.net/npm/@graphiteds/core@1.8.1/dist/core/core.esm.js"
integrity="sha256-ZgEAIlF82yxuNWEeIbGr4hy2yHoNcBET/AZCKlDJnzc="
crossorigin="anonymous"
>
</script>

Then you can use the elements anywhere in your blade templates, but you have to use wire:ignore.

This is because Livewire's DOM diffing doesn't play nice with Web Components which can set attributes on their host element (like a class for styling or aria attributes for accessibility). If you don't add wire:ignore, we can't guarantee the components work correctly and are accessible.

For example:

<gr-button wire:click="increment" variant="primary" circle wire:ignore>
<div slot="icon-only">+</div>
</gr-button>

Warning: You can't use dynamic php variables in attributes because of the required wire:ignore. For example, to show error messages as invalid-text. To work around this, you have to use AlpineJS.

Add the following code to the head of your page:

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3/dist/cdn.min.js"></script>

Add x-data & x-init attributes to a wrapper around your form elements, and set errors to the $errors php variable:

<div x-data="{ 'errors': [] }" x-init="errors = {{ $errors }}"></div>

Use the AlpineJS errors variable in x-bind attributes, for example:

<gr-input
label="Naam"
x-bind:invalid="errors.hasOwnProperty('name')"
x-bind:invalid-text="errors.hasOwnProperty('name') ? errors.name[0] : ''"
wire:model.debounce.500ms="name"
wire:gr-blur="touch('name')"
wire:ignore
required-indicator
>
</gr-input>

Warning: wire:model only works with gr-input & gr-textarea. For other form elements, like gr-radio-group, you have to utilize the gr-change event, like this: wire:gr-change="$set('exampleProperty', $event.target.value)".

Note: All components are only lazy-loaded by the browser when needed. This can introduce some Cumulative Layout Shift (CLS). To reduce this, you can move the components below the fold (outside the visible viewport of the user, or use a bundler with cherry-picked components.

Usage with Inertia.js

Follow the instructions above for your client-side framework of choice.

You can use links like this:

<inertia-link as="gr-button" variant="primary" :href="route('organizations.create')">
Create organization
</inertia-link>

Or like this:

<gr-button variant="primary" @click="$inertia.visit(route('organizations.create'))">
Create organization
</gr-button>

The above examples are using Vue 2. For other frameworks it might differ slightly. Refer to the Links and Manual visits pages in the Inertia.js docs for more help.

Usage with other frameworks

You can either use the @graphiteds/core package directly or load the components from our CDN. Please see Custom Elements Everywhere for more details about wider support in Frameworks like Preact, Svelte, Solid, Riot.js and similar.