Build your own component
Let's create a dropdown component to add to the dashboard that we created earlier.

Create a new folder for our component
Inside src/embeddable.com/components/examples
let's create a folder called ExampleDropdown
.
Add the React.js component code
Inside this folder create a file named index.tsx
(src/embeddable.com/components/examples/ExampleDropdown/index.tsx
).
This will contain the React.js logic for our component.
Use the following content:
//
// src/embeddable.com/components/examples/ExampleDropdown/index.tsx
//
import React, { useState, useEffect, ChangeEvent } from 'react';
import Spinner from '../Spinner';
import Error from '../Error';
import { inputStyles } from '../styles';
import { Dimension, DataResponse } from '@embeddable.com/core';
type ChangeCallback = (chosen: string | null) => void;
type Props = {
defaultValue: string;
onChange: ChangeCallback;
values: Dimension; // Expected: { name: string; title: string; }
results: DataResponse; // Expected: { isLoading: boolean; error?: string; data?: Array<Record<string, string>> }
};
const NO_VALUE = 'NO_VALUE';
const DropdownSelect: React.FC<Props> = ({ defaultValue, onChange, results, values }) => {
const { isLoading, data = [], error } = results;
const [value, setValue] = useState<string>(defaultValue);
// if a default value has been provided, use that.
useEffect(() => {
setValue(defaultValue);
}, [defaultValue]);
// fire the onChange listener if user changes the selected value
const handleChange = (e: ChangeEvent<HTMLSelectElement>) => {
const newValue = e.target.value;
setValue(newValue);
onChange(newValue === NO_VALUE ? null : newValue);
};
// show a spinning loader until we've retrieved the list of values to show from the database.
if (isLoading) return <Spinner />;
// in case there's an error retrieving the list of values, show the error.
if (error) return <Error msg={error} />;
// use a standard HTML `select` input for the dropdown.
return (
<select style={inputStyles} value={value} onChange={handleChange}>
<option value={NO_VALUE}>--no value--</option>
{data.map((option, index) => (
<option key={index} value={option[values.name]}>
{option[values.name]}
</option>
))}
</select>
);
};
export default DropdownSelect;
There is nothing Embeddable-specific here (except some convenient typescript type definitions). This is just a standard React select
component that fires the provided onChange
listener if the user interacts with it.
Tell Embeddable about our component
Inside the ExampleDropdown folder let's now create a file named ExampleDropdown.emb.ts
(src/embeddable.com/components/examples/ExampleDropdown/ExampleDropdown.emb.ts
).
The .emb.ts
file is a special companion file that Embeddable looks for. Embeddable will only pay attention to files that are reachable from .emb.ts
files.
This file tells Embeddable that this is a component that should be usable in the Embeddable platform. It also tells Embeddable what input choices should be made available to the user of your component.

Put the following content in the file:
//
// src/embeddable.com/components/examples/ExampleDropdown/ExampleDropdown.emb.ts
//
import {
EmbeddedComponentMeta,
Inputs,
defineComponent,
} from '@embeddable.com/react';
import { loadData, Value } from '@embeddable.com/core';
import Component from './index'; // the React component we've defined above
export const meta = {
name: 'ExampleDropdown', // this name must match the name of the file (before the `.emb.ts` part)
label: 'Example Dropdown', // human readable name for the component
category: 'Examples', // organise your components into categories
// the width and height (in px) that the component will default to when added to the canvas
defaultWidth: 320,
defaultHeight: 50,
// these are the inputs that the user of your component will be able to interact with
inputs: [
{
name: "ds",
type: "dataset", // this tells Embeddable to render a dropdown with the available datasets
label: "Dataset to display",
category: 'Configure chart',
description: 'The dataset to load the values from'
},
{
name: "values",
type: "dimension", // this tells Embeddable to render a dropdown with the available dimensions
label: "Values",
required: true, // users of your component will be required to provide a value for this input.
config: {
dataset: "ds", // this matches the `name` of the input above
},
category: 'Configure chart',
description: 'The choice of values'
},
{
name: 'defaultValue',
type: 'string', // this tells Embeddable to render a text input
label: 'Default value',
category: 'Configure chart',
description: 'The initial value'
},
],
events: [
{
// this tells Embeddable that this component can fire an event.
// This will mean that users of your component can define an Interaction for it (such as setting a variable).
name: 'onChange',
label: 'Change',
properties: [
{
name: 'chosenValue', // tells Embeddable that the event will have a payload of one string, called `chosenValue`
type: 'string'
}
]
}]
} as const satisfies EmbeddedComponentMeta;
// `defineComponent` is what tells Embeddable that this is a component
export default defineComponent(Component, meta, {
props: (inputs: Inputs<typeof meta>) => {
return {
...inputs,
// load data from the database, based on the choice of inputs provided by the user of your component
// and put the results into a `prop` called `results`
results: loadData({
from: inputs.ds,
select: [inputs.values]
}),
};
},
events: {
// this takes the `value` passed to `onChange` in the react component, and passes it to `chosenValue` which is defined in the `events` above.
onChange: (value) => ({ chosenValue: value || Value.noFilter() })
}
});
Learn more about defining components, loading data and adding interactivity.
Test your component using embeddable:dev
Now to test out your new dropdown component you could build
and push
it to your workspace, but this is a time-consuming way to iterate on components.
That's why Embeddable offers embeddable:dev
.
Simply run npm run embeddable:dev
from the root of your repo and it should spin up a special "local" workspace that allows you to build dashboards using your local components and models (learn more).
Any changes you make to your components or models in this embeddable:dev
workspace should cause the workspace to refresh and instantly show you the effect of the latest changes 🚀.


Congratulations! You've created your first Embeddable component 🎉.