Ready to take your HubSpot customization skills to the next level? In Part 1 of our guide, we laid the foundation by understanding the difference between custom and CRM cards and installing a sample custom card. Now, it's time to roll up your sleeves and dive deeper into the world of custom cards in HubSpot. In Part 2, we'll focus on harnessing the power of React, a powerhouse JavaScript library, to build custom cards that perfectly align with your business objectives.
Plus, you’ll learn how to set up your local environment, so you'll have a safe space to test and refine your creations before unleashing them to the world. Get ready to unlock the full potential of HubSpot customization – let's dive in!
With your sample card set up, you’re ready to start building a custom card from scratch. First, you’ll utilize the VS Code-terminal to create all the folders and files for the initial configuration. These files will be blank initially. Later on, you’ll revisit them to input the code in subsequent steps.
Here is the corrected version of your list:
2. Open up your newly created folder in VS Code and initialize the HubSpot CLI:
hs init |
3. Next, run the following command to generate a new project that will serve as the container for or your application within your account:
hs project create |
4. The HubSpot CLI now prompts you with a set of inquiries, covering the project's name, location, and template preferences:
These actions will generate a new folder named “src” along with a hsproject.json file.
5. Add the package.json file – optional but highly recommended because this will simplify your life slightly by eliminating the need to navigate to other directories for installing dependencies:
cd customCard2 |
For Mac-users:
touch package.json |
For Windows-users:
New-Item package.json |
6. Add the structure for a private app, which is necessary for UI extensions to function and can be used for multiple custom cards, by running the following commands, one after another, still in the VS Code terminal of your main folder:
cd src |
mkdir app |
cd app |
For Mac-users:
touch app.json |
For Windows-users:
New-Item app.json |
7. Next, create the extensions folder and the files “custom-card.json”, “CustomCard.jsx or CustomCard.tsx” and “package.json” (can be shared among multiple cards) by heading to the app folder and running the following commands in your terminal:
mkdir extensions |
cd extensions |
For Mac-users:
touch associated-deals.json |
For Windows-users:
New-Item associated-deals.json |
For Mac-users:
touch AssociatedDeals.jsx |
For Windows-users:
New-Item AssociatedDeals.jsx |
For Mac-users:
touch package.json |
For Windows-users:
New-Item package.json |
8. If you wish to delve further into your CRM or interact with data beyond, serverless functions are the logical next step. For example, you can use a serverless function to interact with a HubDB table hosted on another HubSpot account.
To store serverless functions you need to create another folder(“app.functions”) and additional three files (“functionName.json”, “serverless.json” and “package.json”).
To do so navigate out of the extensions folder and back into the app folder where you run the following commands in your terminal, one after another:
cd .. |
cd app.functions |
For Mac-users:
touch thanksKyle.js |
For Windows-users:
New-Item thanksKyle.js |
For Mac-users:
touch serverless.json |
For Windows-users:
New-Item serverless.json |
For Mac-users:
touch package.json |
For Windows-users:
New-Item package.json |
For Mac-users:
touch .env |
For Windows-users:
New-Item .env |
Let’s pause here for a minute and celebrate: The structure for your custom card is set up – congratulations on coming so far!
9. Now, let’s add some content with the help of the optional package.json file from step 5:
{ "name": "customcard2", "version": "0.1.0", "scripts": { "postinstall": "cd ./src/app/extensions/ && npm install && cd ../app.functions && npm install" }, "author": { "name": "your first name your last name", "email": "yourname@youremailprovider.com" }, "license": "MIT" } |
10. Next, create the necessary private app by filling in the data in the app.json file located in the app folder running the following code in your terminal:
{ "name": "Myfirstcustomcard", "description": "The description of my first custom card", "uid": "my-first-custom-cards-uid-which-cannot-be-changed-afterwards" "scopes": [ "crm.objects.contacts.read" ], "public": false, "extensions": { "crm": { "cards": [ { "file": "extensions/associated-deals.json"}] } } } |
11. Then, you are ready to input the codes for the custom card. Add the following lines to the following files located in the extensions folder:
{ "type": "crm-card", "data": { "title": "My first custom card", "uid": "my-first-custom-cards-uid-which-cannot-be-changed-afterwards", "location": "crm.record.tab", "module": { "file": "AssociatedDeals.jsx" }, "objectTypes": [ { "name": "contacts" } ] } } |
import Reactfrom "react"; |
{ "name": "myfirstcustomcard-extension", "version": "0.1.0", "author": "Your First Name Your Last Name", "license": "MIT", "scripts": { "dev": "hs project dev" }, "dependencies": { "@hubspot/ui-extensions": "latest", "react": "^18.2.0" } } |
12. Now, let’s input the codes for the serverless functions. Add the following lines to the following files located in the app.functions folder:
{ "name": "hubdb_updater", "version": "0.1.0", "author": "Your First Name Your Last Name", "license": "MIT", "dependencies": { "axios": "^0.27.2" } } |
const axios = require('axios'); exports.main = async () => {} |
{ "appFunctions": { "jepsonupdater": { "file": "thanksKyle.js", "secrets": [] } } } |
13. Finally, save your project (via “File” → “Save” or the keyboard shortcut “Control + S”) and you’re ready to upload your custom card to your HubSpot test account:
npm install |
hs project upload |
Once you have your card's basic structure in place, it's time to add functionality. This includes handling user interactions, fetching data from external sources, and updating the card's display accordingly. You'll use JavaScript and HubSpot APIs to implement the desired functionality. Again: don't worry if you're not familiar with all of these – we'll walk you through each step of the process.
Initially, you'll start your local development server to facilitate the creation of your cards. Through local development, you can confidently build and test your card without worrying about affecting the production card until you upload your changes.
hs project dev |
18. Now finish building your custom card by adding codes to the following three components you’ve just created:
// first we need to import the Flex component from the ui-extensions package import {Flex} from '@hubspot/ui-extensions'; // then we will create a functional component that takes in two props, stats and clicker export const Layout = ({ stats, clicker }) => { return ( <Flex direction="row" align='start'> |
// first we need to import the Flex component from the ui-extensions package |
import { Button } from "@hubspot/ui-extensions"; |
19. Next, open the parent component “AssociatedDeals.jsx” and overwrite the existing code with the following one:
import React from "react"; |
Meanwhile, content is displaying in your custom card, but it's not yet functional:
Let's continue to make it useful for you:
20. Create the panel of the custom card which will consist of the files DealPanel.jsx and DealPanelInner.jsx:
import { |
import { Text, Flex } from '@hubspot/ui-extensions'; |
21. Finally, open the parent component “AssociatedDeals.jsx” again and overwrite the existing code with the following one:
import React from "react"; |
Don’t forget to save your project (via “File” → “Save” or the keyboard shortcut “Control + S”)!
Congratulations again! At this stage, you have built a fully operational custom card capable of displaying high- and low-level associated deal information for a contact in a table.
Check it out by navigating to a contact record in your test-account and take a look at your custom card:
Now you have two options:
Either, if you prefer to focus on completing your existing custom card, you can skip the next chapter and continue with “Testing Your Custom Card.”
Or, if you’re feeling up to the challenge of enhancing your CRM card further, let’s integrate a button that utilizes a serverless function to update a HubDB table.
Let's explore a bonus that adds an extra layer of functionality to your CRM card: serverless functions. While not essential for the basic functionality of a custom card, serverless functions can significantly enhance its capabilities by enabling dynamic interactions, data processing, and seamless integration with external resources.
For this example, you'll be utilizing a HubDB table graciously provided by HubSpot, along with the sample website thanks.kyle.team. So, let's express our gratitude to Kyle and Dennis from HubSpot by constructing this serverless function together.
22. open the parent component “AssociatedDeals.jsx” again and add a button component by replacing the existing code with the following one:
import React from "react"; |
Now, on the front end, you've implemented a button click that activates a serverless function called "jepsonupdater":
You may remember that you specified the name of the serverless function in your serverless.json file here. In order for this serverless function to make an authenticated API call, you need to store the authentication method in a so-called “secret”:
23. Open the serverless.json file located in the app.functions folder and overwrite the existing code with the following one:
{ |
24. Now, to register the secret with HubSpot you need to stop watching the project by navigating to your terminal and hitting “Control” + “c” on your keyboard.
25. Then, add the following in your terminal and press “Enter”:
hs secrets add hubdb |
26. You’ll be asked to enter a value for your secret. Copy & paste the following key in your terminal:
pat-na1-bccb209f-d999-4dcc-85ee-d2da7c875d62 |
Attention: you won’t see any asterisks or similar when pasting the key. Just hit “Enter” when you’re done.
Great, you've successfully registered the token with HubSpot! However, due to security protocols, it won't be accessible for local development. Therefore, you must also include it in the .env file which you have created before in this step:
27. Head over to your terminal again and get the Development server back up and running by executing the following command:
hs project dev |
28. Choose “Test on this production account” and press “Enter” on your keyboard.
29. Open the .env file in your app.functions folder and add the following:
hubdb=pat-na1-bccb209f-d999-4dcc-85ee-d2da7c875d62 |
30. Don’t forget to save your project!
31. To create your serverless function, open up the thanksKyle.js file and replace the existing entry with the following one:
const axios = require('axios'); |
32. Finally, save your project (via “File” → “Save” or the keyboard shortcut “Control + S”) and go to your contact record in your HubSpot test account.
33.Test your card by clicking on the “Jepson Button.” You've succeeded if the image of Kyle on the page thanks.kyle.team becomes increasingly clearer with each click of the button until reaching full opacity:
After completing the construction of your custom cards, we’re sure you’re highly eager to deploy and utilize it. However, prior to deployment, it's crucial to allocate sufficient time to the next step: testing.
Thorough testing of your custom card is imperative to verify its functionality before releasing it into production. Remain within the local development environment to conduct comprehensive testing across different scenarios, ensuring that the card performs as intended. Resolve any encountered issues or bugs during the testing phase before proceeding with deployment.
Trust us, investing time in thorough testing now will save you time and trouble in the long run, so it’s better not to neglect it!
Once you're confident that your custom card is functioning correctly, it's time to deploy it to your HubSpot account. That’s when you have to execute the upload command one final time to push your changes. So run the following code in your VS Code terminal:
hs project upload |
And there you have it – your first HubSpot custom card! By mastering the fundamentals of custom card development, you're now equipped to create innovative and engaging experiences for HubSpot users, opening up endless possibilities for extending HubSpot's functionality.
This guide only scratches the surface of what's possible, so keep exploring and building!
Check out HubSpot sample cards for inspiration and don’t forget to test your custom cards thoroughly before deploying them.
If you have any questions or need further assistance, feel free to reach out to us for support. Happy coding!