Building components
Defining components

Defining Components

You can create custom React components in Embeddable using any JS libraries you like.

Key capabilities include:

  • Define Inputs: Make re-usable components by defining inputs your team can customize in the builder.
  • Load Data: Dynamically fetch data from your database via Embeddable's loadData function.
  • Pass Events: Capture user actions (e.g. button clicks) and send them back to Embeddable for interactive features like filtering.

How It Works

Build Your React Component (.tsx)

Write a standard React component - handling your UI, props, and business logic.

For example, this simple text component displays a title and body:

// src/components/TextComponent/index.tsx
 
import React from 'react';
 
type Props = {
  title: string;
  body: string;
};
 
export default ({ title, body }: Props) => {
  return (
    <div>
      <h1>{title}</h1>
      <p>{body}</p>
    </div>
  );
};

There's nothing Embeddable-specific about this code - it's just standard React.

Configure in .emb.ts

In a companion .emb.ts file, define inputs and other configuration, including how to load data. This file tells Embeddable how to expose the component in the no-code builder so it can be configured by your team without code:

// src/components/TextComponent/TextComponent.emb.ts
 
import { EmbeddedComponentMeta, defineComponent } from '@embeddable.com/react';
import Component from './index';
import { Inputs } from '@embeddable.com/react';
 
export const meta = {
  name: 'TextComponent', // a unique identifier that must match the file name (i.e. TextComponent.emb.ts)
  label: 'Text component', // user-facing name in the builder
  inputs: [
    {
      name: 'title', // unique identifier for this input
      type: 'string',  // determines the UI control to render (i.e. a text field in this case)
      label: 'Title', // the label shown in the builder
    },
    {
      name: 'body', // unique identifier for this input
      type: 'string', // renders a second text field. 
      label: 'Body', // the label shown in the builder
    }
  ]
} as const satisfies EmbeddedComponentMeta;
 
//The function that tells the SDK to include this component in the no-code builder.
export default defineComponent(Component, meta, {
  props: (inputs: Inputs<typeof meta>) => {
    return {
      // the inputs are passed through to the React component as props
      title: inputs.title,
      body: inputs.body
    };
  }
});

Two things to notice:

  1. inputs tells Embeddable which input fields to show in the UI when using this component. In this case, two text input fields.
  2. props is a function that takes those inputs and maps them onto the props that should be passed into the React component when rendering.

Push to Embeddable

Run npm run embeddable:dev to test out your component, and when you’re happy with it, push your component code to Embeddable. Your teammates can now drag, drop, and configure it in their dashboards - no extra coding required.

Image 0Image 1

Example: a simple data component

Below is a simple KPI chart component that loads data from your database:

// src/components/KPIChart/index.tsx
 
import React from 'react';
import { DataResponse, Measure } from '@embeddable.com/core';
import Loading from '../util/Loading'
import Error from '../util/Error'
 
type Props = {
  title?: string;
  metric?: Measure; // { name, title }
  results: DataResponse; // { isLoading, error, data: [{ <name>: <value>, ... }]
};
 
export default ({ title, metric, results }: Props) => {
 
  const { isLoading, data, error } = results;
 
  if(isLoading) {
    return <Loading />
  }
 
  if(error) {
    return <Error msg={error}/>;
  }
 
  const value = results.data?.[0]?.[metric.name] ?? 'No data';
 
  return (
    <div>
      {title && <h1>{title}</h1>}
      <p>{value}</p>
    </div>
  );
};

And its .emb file, defining the inputs and configuration:

// src/components/KPIChart/KPIChart.emb.ts
 
import { EmbeddedComponentMeta, defineComponent, Inputs } from '@embeddable.com/react';
import { loadData } from '@embeddable.com/core';
import Component from './index';
 
export const meta = {
  name: 'KPIChart', // an identifier - must match KPIChart.emb.ts
  label: 'KPI Chart', // user-facing name in the builder 
  inputs: [
    {
      name: 'title',
      type: 'string',
      label: 'Title text',
    },
    {
      name: 'ds',
      type: 'dataset', // shows a dropdown of available datasets. These are created directly in the Builder.
      label: 'Dataset',
    },
    {
      name: 'metric',
      type: 'measure', // shows a dropdown of measures (defined in your data models)
      label: 'KPI',
      array: false, // specifies that users can select a single measure 
      config: {
        dataset: 'ds', // restricts measure options to the selected dataset
      }
    },
  ]
} as const satisfies EmbeddedComponentMeta;
 
//The function that tells the SDK to include this component in the no-code builder.
export default defineComponent(Component, meta, {
  props: (inputs: Inputs<typeof meta>) => {
    return {
      ...inputs, // the inputs are passed through to the component as props
      results: loadData({ // fetches data from your database and passes it to your component
        from: inputs.ds,
        measures: [inputs.metric], 
      })
    };
  }
});

The defineComponent and loadData functions used above are two of the most powerful parts of the Embeddable SDK. You can learn more about them here: defineComponent and loadData.