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!
Building Your Own Custom Card
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.
Define the structure of your custom card
- Create a new folder on your computer desktop and name it something like “customCard2” or whatever.
Attention: If your folder names contain spaces, VS Code cannot process them and will consistently generate a “too many arguments" error. Therefore, it's advisable to avoid using spaces in names altogether.
Here is the corrected version of your list:
2. Open up your newly created folder in VS Code and initialize the HubSpot CLI:
- …either by using the HubSpot extension in VS Code like you did before. Then, you may skip the next steps and continue with step 3.
- …or by running the following command in the terminal of VS Code, which asks you to open your HubSpot account and copy your personal access key:
hs init |
- Hit “y” for “Yes” and “Enter” on your keyboard.
- Open your HubSpot test account.
- Click on “Show” under your hidden personal access key:
- Copy your revealed personal access key.
- Paste your key in to your VS Code terminal and hit “Enter”.
- Accept the default name for the account in the HubSpot CLI by hitting “Enter” again.
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:
-
- Name your project “customCard2”
- Opt for the default location
- Select no template.
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:
- Head to the main folder in your VS Code terminal >again and run the following commands, one after another:
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 |
Add codes to your custom card
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:
- To execute the scripts in the extensions and app.functions package.json file, navigate to the empty package.json file situated at the root level of your project in VS code, and append the following lines:
Attention: Especially for future use, you'll need to customize the code slightly as shown in the red-highlighted phrases below.
{ "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:
-
- associated-deals.json:
{ "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" } ] } } |
- AssociatedDeals.jsx (the react file):
import Reactfrom "react"; |
- package.json (for the front-end):
{ "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:
-
- package.json:
{ "name": "hubdb_updater", "version": "0.1.0", "author": "Your First Name Your Last Name", "license": "MIT", "dependencies": { "axios": "^0.27.2" } } |
- thanksKyle.js (serverless function file which will be relevant in the bonus part of this guide):
const axios = require('axios'); exports.main = async () => {} |
- serverless.json (for the back-end):
{ "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:
-
- Return to the terminal and ensure you're in the root directory, which is the one containing the hsproject.json file:
- Once there, execute the following commands one after another:
npm install |
hs project upload |
- Check if everything proceeded smoothly, by logging in to your test account and adding this card to contact records.
Specify the functions of your custom card
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.
- Go to your terminal in VS Code again where you’ve left and run the following command:
hs project dev |
- Since there are no sandboxes in HubSpot test accounts, choose “Test on this production account” instead and press “Enter” on your keyboard.
- Open your HubSpot test account and go to a contact record displayed with a label above, indicating that you're actively developing this custom card. This visibility is exclusive to you and not visible to anyone else:
- Prior to implementing functionality into the custom card, let's enhance the organization of your React components:
- Go to the extensions folder in VS Code, right-click on it, select “New Folder…” in the context menu and name it “components”:
- Within this folder, create the following 5 files:
- Clicker.jsx (“View More Button”)
- DealPanel.jsx (the outer level of the panel)
- DealPanelInner.jsx (where you can see the data that you receive for the panel)
- Layout.jsx (controls the layout for the component)
- Stats.jsx (the component that shows the data before you open the panel)
18. Now finish building your custom card by adding codes to the following three components you’ve just created:
-
- Layout.jsx:
// 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'> |
- Stats.jsx:
// first we need to import the Flex component from the ui-extensions package |
- Clicker.jsx:
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:
- Open “DealPanel.jsx” and copy / paste the following code:
import { |
- Open “DealPanelInner.jsx” and copy / paste the following code:
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.
Bonus: Adding a button to your custom card by using a serverless function
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:
Note: You may notice that when accessing the public landing page, Kyle is already fully visible due to someone successfully testing the serverless function before and not resetting the image to its original settings. In that case, another challenge awaits you: Add a reset button to your custom card so that which each click the image's transparency returns to 100%.
Testing Your Custom Card
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!
Deploying Your Custom Card
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 |
Achievement Unlocked: 1st Custom Card Created
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!