How to Use Chart.js in Retool Using a Custom Component.

Saunak Surani
Widle Studio LLP
Published in
4 min readJun 26, 2024

Retool provides a versatile platform for building internal tools quickly, and one of the best ways to extend its functionality is through custom components. In this article, we’ll walk through the process of integrating Chart.js in Retool using a custom React component. We’ll use sample data representing students’ ages for demonstration. Follow these steps to visualize your data in a pie chart using Chart.js.

Chart.js in Retool Using a Custom Component

Sample Data

We’ll use the following data to create our pie chart. This data will be included in the model of the custom component:

{
"data": {
"x": ["Below 14", "14-16", "16-18", "18-20", "20-22", "22-24", "Above 24"],
"y": [29.79, 4.26, 0, 4.26, 34.04, 4.26, 23.4]
}
}

HTML Structure

Start by setting up the basic HTML and CSS structure within your Retool custom component:

<style>
.component {
border: 1px solid #CDA6DF;
width: 100%;
height: 100%;
border-radius: 12px;
background-color: #FFFFFF;
padding: 10px;
box-sizing: border-box;
}
.main {
background-color: #F2ECF5;
padding: 10px;
margin-top: 10px;
border-radius: 12px;
}
.root, .unique {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.first, .second {
border-bottom: 1px solid #CDA6DF;
color: #000000;
width: 100%;
font-family: 'Poppins', sans-serif;
font-size: 14px;
font-weight: 400;
line-height: 18px;
text-align: center;
}
.line {
height: 30px;
}
.percentage {
font-family: 'Poppins', sans-serif;
font-size: 24px;
font-weight: 400;
line-height: 31px;
text-align: center;
}
#myChart {
margin: 0 auto;
height: 380px !important;
width: 380px !important;
}
.title {
font-family: 'Poppins', sans-serif;
font-size: 18px;
font-weight: 400;
line-height: 23px;
color: #7C3C9B;
text-align: center;
}
.no-data {
text-align: center;
color: #BFBFBF;
font-family: 'Poppins', sans-serif;
font-size: 18px;
font-weight: 400;
line-height: 23px;
height: 325px;
display: flex;
justify-content: center;
align-items: center;
}
</style>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div id="react"></div>

Creating the React Component

Next, we’ll create a React component that renders the Chart.js pie chart using the sample data. Add the following script to your custom component:

<script type="text/babel">
const { useEffect, useRef } = React;
const MyCustomComponent = ({ model }) => {
const colors = [
'#FD6AF8',
'#41B54A',
'#F7971C',
'#2D67B1',
'#555555',
'#EC1F24',
'#C561F7'
];
const chartRef = useRef(null); // Ref to store chart instance
const prevDataRef = useRef([]); // Ref to store previous data
// Helper function to check if all values in an array are null
function allValuesAreNull(arr) {
return arr.every(value => value === null);
}
useEffect(() => {
const ctx = document.getElementById("myChart").getContext("2d");
// Function to destroy the chart
const destroyChart = () => {
if (chartRef.current) {
chartRef.current.destroy();
chartRef.current = null;
}
};
// Function to create or update the chart
const createOrUpdateChart = () => {
if (!chartRef.current) {
chartRef.current = new Chart(ctx, {
type: 'pie',
data: {
labels: model.data.x,
datasets: [{
label: 'Ages in %',
data: model.data.y,
backgroundColor: colors,
borderColor: "#FFFFFF",
borderWidth: 1.5,
}]
}
});
} else {
chartRef.current.data.labels = model.data.x;
chartRef.current.data.datasets[0].data = model.data.y;
chartRef.current.update();
}
prevDataRef.current = model.data.y;
};
// Create chart if there's data
if (!allValuesAreNull(model.data.y)) {
createOrUpdateChart();
} else {
destroyChart();
}
// Cleanup on component unmount
return destroyChart;
}, [model.data, colors]);
if (allValuesAreNull(model.data.y)) {
return (
<div className="component">
<span className="title">Ages of players</span>
<div className="no-data">No Data Found</div>
</div>
);
}
return (
<div className="component">
<span className="title">Ages of players</span>
<canvas id="myChart" width="400" height="400"></canvas>
<div className="main">
{model.data.x.map((age, index) => (
<div className={index === 6 ? "unique" : "root"} key={index}>
<div className="first">
Age {index === 0 || index === 6 ? age : `between ${age}`}
&nbsp;&nbsp;<span className="percentage" style={{ color: colors[index] }}>
{model.data.y[index]}%
</span>
</div>
{index % 2 !== 0 && <div className="line"></div>}
</div>
))}
</div>
</div>
);
};
const ConnectedComponent = Retool.connectReactComponent(MyCustomComponent);
const container = document.getElementById("react");
const root = ReactDOM.createRoot(container);
root.render(<ConnectedComponent />);
</script>

Explanation

  1. HTML and CSS Structure: Define the basic styles and structure of the component to ensure it fits well within the Retool dashboard.
  2. React Component Setup: Use React’s useEffect hook to manage the lifecycle of the Chart.js instance, creating or updating the chart based on the provided model data.
  3. Helper Functions:allValuesAreNull: Checks if all values in the data array are null.
  4. Chart Management:
    - createOrUpdateChart: Either create a new chart or update the data in the existing chart.
    - destroyChart: Destroys the chart if there is no valid data or when the component unmounts.
  5. Data Handling: Checks if there’s data to display; if not, it renders a “No Data Found” message.
  6. Component Mounting: Use Retool’s Retool.connectReactComponent to connect the custom React component with the Retool framework.

Conclusion

By following these steps, you can successfully integrate Chart.js within a Retool custom component to visualize data with interactive pie charts. This approach offers flexibility, allowing you to further customize the chart according to your application’s needs.

Experiment with different chart types and data sets to unlock the full potential of custom components in Retool, enhancing your internal tools and dashboards.

--

--

Saunak Surani
Widle Studio LLP

Passionate about technology, design, startups, and personal development. Bringing ideas to life at https://widle.studio