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 {
...inputs // the inputs are passed through to the component as props
};
}
});
Push to Embeddable
When you’re done, push your component code to Embeddable. Your teammates can now drag, drop, and configure it in their dashboards - no extra coding required.
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 loadData
function used above is one of the most powerful parts of the Embeddable SDK. You can learn more about it here.
The defineComponent
Function
The defineComponent
function, used inside your emb.ts
files, is how you register and configure components in Embeddable.
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
};
},
});
Parameters
When you call defineComponent
in your .emb.ts
file, you pass in three arguments:
Param | Type | Required |
---|---|---|
component | Component | ✅ Yes |
meta | Meta | ✅ Yes |
config | Config | ✅ Yes |
component
: your React component.meta
: an object defining how the component appears and which inputs are available in the builder.config
: an object specifying how user inputs map to props, how local state is managed, and how events are handled.
1. component
component
is simply your React component:
import Component from './index';
2. meta
meta
is the second argument to defineComponent
. It governs how a component is displayed and configured in the builder, including the inputs it needs.
import { EmbeddedComponentMeta } from '@embeddable.com/react';
export const meta = {
name: 'MyComponent',
label: 'My Component',
category: 'Charts',
classNames: ['container'],
defaultWidth: 200,
defaultHeight: 100,
inputs: [...],
events: [...],
variables [...],
} as const satisfies EmbeddedComponentMeta;
Param | Type | Required |
---|---|---|
name | string | ✅ Yes |
label | string | ✅ Yes |
classNames | string[] | ❌ No |
defaultWidth | number | ❌ No |
defaultHeight | number | ❌ No |
inputs | InputMeta[] | ❌ No |
events | EventMeta[] | ❌ No |
variables | VariableMeta[] | ❌ No |
name
: A unique identifier that must match the.emb.ts
filename. Changing it later can break references.label
: A user-facing name shown in the builder.classNames
: CSS class names for styling the container.inputs
: Input fields users configure (e.g.strings
,numbers
,datasets
, as well as custom types).defaultWidth
/defaultHeight
: Initial size in the builder (in pixels, snapped to a grid).events
: Specifies events the component can trigger (e.g.onChange
,onClick
), which is key to interactivity. Learn more about events here.variables
: Auto-creates variables in the no-code Builder when the component is used, which are key to interactivity. Learn more about variables here.
InputMeta
Definition
export const meta: EmbeddedComponentMeta = {
name: 'BasicDropdownComponent',
label: 'Basic Dropdown',
inputs: [
{
name: 'ds',
type: 'dataset',
label: 'Dataset',
description: 'Dataset',
category: 'Dropdown values'
},
{
name: 'property',
type: 'dimension',
label: 'Property',
config: {
dataset: 'ds',
supportedTypes: ['time'] // Only let user pick time dimensions
},
category: 'Dropdown values'
},
...
]
}
Param | Type | Required |
---|---|---|
name | string | ✅ Yes |
type | CustomType or NativeType | ✅ Yes |
label | string | ✅ Yes |
description | string | ❌ No |
defaultValue | any | ❌ No |
config | object | ❌ No |
array | boolean | ❌ No |
category | string | ❌ No |
name
: A unique identifier for this input (within the component).type
: Determines the UI control (e.g.,string
,dimension
, or custom). Native types are described below.label
: User-facing label in the builder.description
: A helpful reference, not currently displayed in the builder.defaultValue
: The initial value for the input.category
: Assigns an optional grouping for this input in the builder UI. Inputs sharing the same category appear together.config
: An arbitrary JS object that is type-specific. Theconfig
object is passed to the no-code editor to enable custom behavior. A common use-case includes specifying the dataset fordimension
ormeasure
inputs and limiting the options that display based on their type.array
: Allows users in the builder to select or add multiple values. Applies to inputs of typedimension
,measure
, andstring
.
Native Input Types
When defining inputs
in your .emb.ts
file, you can select from a set of native types that Embeddable supports by default. Each type dictates which UI control appears in the no-code builder and how the data is passed to your component.
string
renders a text input in the builder.number
renders a numeric input in the builder.boolean
renders a dropdown (true/false) in the builder.time
represents a single point in time, either absolute or relative.// Absolute date const t1: Time = { date: new Date(1980, 3, 28) } // Relative date const t2: Time = { relativeTimeString: 'last week' }
timeRange
represents a range between two time points, either absolute or relative.// Absolute from / to const tr1: TimeRange = { from: new Date(1995, 1, 16), to: new Date() } // Relative const tr2: TimeRange = { relativeTimeString: 'last 30 days' }
dataset
lets users pick a dataset in the builder.measure
represents a measure (count, sum, etc.), as defined in your data models.dimension
represents a dimension (e.g. group by country or category), as defined in your data models.granularity
for grouping time dimensions inloadData
.const g: Granularity = 'day' // or 'week', 'month', 'year', etc.
dimensionOrMeasure
represents an input that can be either a dimension or a measure, letting the user choose in the builder.
If you need more specialized behavior than these native types provide (e.g., custom date pickers or advanced styling), you can define custom types along with a custom editor. These built-in types, however, cover most standard use cases for text, numbers, booleans, time inputs, and data references.
EventMeta
Definition
Events are used to create interactive components. For example, a dropdown containing a list of countries that, when clicked, filters the data. Or a set of buttons showing 'day', 'week', and 'month' that, when clicked, update the x-axis granularity on a time-series chart.
export const meta: EmbeddedComponentMeta = {
name: 'BasicDropdownComponent',
label: 'Basic Dropdown',
inputs: [],
events: [
{
name: 'onChange',
label: 'Change',
properties: [
{ name: 'value', type: 'string', label: 'Clicked Dimension' },
],
},
]
}
Param | Type | Required |
---|---|---|
name | string | ✅ Yes |
label | string | ✅ Yes |
properties | EventProperty[] | ❌ No |
-
name
: The event handler name passed into your React component. E.g. setting it toonBigClick
means that Embeddable will inject a function into your React component, via its props, calledonBigClick
. When called, the value you pass to this function will be passed toevents.onBigClick
insidedefineComponent
where you need to map the value onto anobject
that has the shape described inevents.properties
in yourmeta
. This allows Embeddable to make your event available to use as an interaction in the no-code builder. -
label
: How this event is labeled in the builder. -
properties
: Describes data passed to Embeddable when the event fires.EventProperty
Definition
Param | Type | Required |
---|---|---|
name | string | ✅ Yes |
type | CustomType or NativeType | ✅ Yes |
label | string | ❌ No |
array | boolean | ❌ No |
name
: The property key in yourevents
mapping (e.g.value
).type
: The expected data type (e.g.string
,number
,boolean
).label
: An optional label for this property in the builder.array
: Allows multiple values if set totrue
.
VariableMeta
Definition
Variables are a core-concept in Embeddable. They are used mainly to store the values passed to Embeddable from events fired by interactive components.
Variables can be created manually in the no-code builder or they can be defined in code and then created automatically. Defining them in code is preferable because it contributes to a faster, more intuitive experience within the builder - especially for non-technical users.
export const meta: EmbeddedComponentMeta = {
name: 'BasicDropdownComponent',
label: 'Basic Dropdown',
inputs: [],
events: [],
variables: [
{
name: 'chosen value',
type: 'string',
defaultValue: Value.noFilter(),
inputs: ['defaultValue'],
events: [{ name: 'onChange', property: 'value' }],
},
]
}
Param | Type | Required |
---|---|---|
name | string | ✅ Yes |
type | CustomType or NativeType | ✅ Yes |
defaultValue | any | ❌ No |
inputs | string[] | ❌ No |
events | EventRef[] | ❌ No |
-
name
: The variable’s name when auto-created in the builder. -
type
: The variable type (string
,boolean
, etc.). -
defaultValue
: The initial value for the variable. -
inputs
: A list of inputs whose value should be linked to the variable. The names must match the name of an input defined ininputs.name
in yourmeta
. -
events
: If you want certain events to update this variable’s value.EventRef
DefinitionParam Type Required name
string ✅ Yes property
string ✅ Yes name
: References an event frommeta.events
.property
: References a property in that event (e.g.,{ name: 'onChange', property: 'value' }
).
3. config
config
is the third argument to defineComponent
. It controls what's passed to your component as props and how local .emb
state (Embeddable State) is managed.
Param | Type | Required |
---|---|---|
props | (inputs: Inputs<typeof meta>, [state, setState], clientContext) => any | ✅ Yes |
events | { [eventName: string]: (payload: any) => any } | ❌ No |
props(inputs, [state, setState], clientContext)
-
inputs
: Values entered by the user in the no-code builder. -
state
andsetState
are state local to the.emb
file, enabling you to pass state from your react component back to the.emb.
file. The most common use-case is to load data dynamically from within the component. -
clientContext
: Any additional data passed in from the web component at embed time (e.g. theming, environment info).export default defineComponent(MyComponent, meta, { props: (inputs, [state, setState], clientContext) => { return { ...inputs, clientContext, // e.g. { theme: 'dark', locale: 'en-US' } }; } });
-
events
describes how events your component triggers are transformed into a data object that Embeddable can use for interactivity, as described inevents.properties
inmeta
.
A Detailed Example
// src/components/Buttons/Buttons.emb.ts
import { Value } from '@embeddable.com/core';
import { EmbeddedComponentMeta, Inputs, defineComponent } from '@embeddable.com/react';
import Component from './index';
export const meta = {
name: 'Buttons', // Must match the .emb.ts filename; unique ID for this component
label: 'Button List', // User-facing name in the builder UI
defaultWidth: 400, // Initial width in pixels when dropped on the canvas
defaultHeight: 80, // Initial height in pixels when dropped on the canvas
category: 'Controls: buttons', // Optional grouping/category in the builder
inputs: [
{
name: 'values',
type: 'string',
array: true, // Allows multiple string values (multi-select)
label: 'Values',
category: 'Button values' // Groups these inputs in the builder UI
},
{
name: 'title',
type: 'string',
label: 'Title',
category: 'Settings' // Another input category for organizational purposes
},
{
name: 'selectedValues',
type: 'string',
array: true,
label: 'Default value',
category: 'Pre-configured variables'
}
],
events: [
{
name: 'onChange', // Event name your React component expects as a prop
label: 'Change', // How this event appears in the builder UI when defining interactions
properties: [
{
name: 'value', // The property name to be passed back
type: 'string',
array: true // Indicates multiple string values can be returned
}
]
}
],
variables: [
{
name: 'chosen value', // Variable created automatically when this component is added
type: 'string',
array: true,
defaultValue: Value.noFilter(), // Initial variable value (if none provided)
inputs: ['selectedValues'], // Connects the variable to the 'selectedValues' input
events: [{ name: 'onChange', property: 'value' }] // On the 'onChange' event, update the 'chosen value' variable with the 'value' property from the event
}
]
} as const satisfies EmbeddedComponentMeta;
export default defineComponent(Component, meta, {
props: (inputs: Inputs<typeof meta>, [state], clientContext) => {
// Maps the inputs defined in meta to the props of your React component
return {
...inputs,
clientContext // e.g. { theme: 'dark', locale: 'en-US' }
};
},
events: {
// Maps the 'onChange' event from your React component to an event described in meta
onChange: (v) => ({ value: v || Value.noFilter() })
}
});