UI extension components (BETA)

APPLICABLE PRODUCTS
  • Sales Hub
    • Enterprise
  • Service Hub
    • Enterprise

When building a UI extension, you'll include any number of HubSpot-provided components to render the extension's UI. There are three types of components to select from:

  • Standard components: raw components that can be used for both internal and external data. These components do not fetch data on their own, but are more flexible in their implementation.
  • CRM data components: out of the box components that can fetch/display only HubSpot data. These components enable easy visualization of account data, including properties, associations, and reports. They also automatically handle permissions, input validation, conditional properties, and more. These components can only be placed in the middle column of CRM records.
  • CRM action components: out of the box actions related to CRM records, engagements, and more. Includes three components and a set of actions that each can perform. For example, use these actions to create new records, schedule meetings, and navigate to other HubSpot pages.

Components are included in the UI Extensions SDK, and should be imported at the top of your jsx or tsx file. Standard components are imported from '@hubspot/ui-extensions' while CRM data and CRM action components are imported from '@hubspot/ui-extensions/crm'.

import { Alert, Text } from '@hubspot/ui-extensions'; import { CrmAssociationPivot, CrmActionLink } from '@hubspot/ui-extensions/crm';
Please note: to access the latest components, ensure that you've installed the latest npm package by running npm i @hubspot/ui-extensions in the extensions directory.

Below, learn about each type of component and how to include it in an extension.

Standard components

Standard components are imported from @hubspot/ui-extensions.

import { Alert, Text } from '@hubspot/ui-extensions';

Accordion

The Accordion component renders a collapsable accordion section that can contain other components.

ui-extensions-accordion-section

title  string (required)

The accordion's title text.

defaultOpen  boolean

Defines default open behavior on page load. When set to true, the accordion will be open by default on initial load.

The open prop takes precedence over this prop.

disabled  boolean

When set to true, the accordion's state cannot be changed.

open  boolean

For controlling the accordion's open state programmatically. When set to true, the accordion will open. Takes precedence over defaultOpen.

onClick  function

A function that will be invoked with the accordion title is clicked. This function receives no arguments and its returned value is ignored.

size  string

The size of the accordion title. Can be one of:

  • xs or extra-small
  • sm or small 
  • md or medium (default)
const Extension = () => { return ( <> <Accordion title="Item One" defaultOpen={true}> <Text>Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.</Text> </Accordion> <Accordion title="Item Two"> <Text>Second inner text</Text> </Accordion> <Divider /> </> ); };

Alert

The Alert component renders a single alert.

ui-ext-components-alert

title  string (required)

The bolded title text of the alert.

variant  string

The color of the alert. The following variants are available:

  • info (default)
  • success
  • warning
  • error
  • danger
const Extension = () => { return ( <> <Alert title="Important Info" variant="info"> This is an informative message. </Alert> <Alert title="Success"variant="success"> Operation completed successfully. </Alert> <Alert title="Warning" variant="warning" > Proceed with caution. </Alert> <Alert title="Error" variant="error" > Something went wrong. Please try again. </Alert> <Alert title="Danger" variant="danger" > This action cannot be undone. Be careful. </Alert> </> ); };

Button

The Button component renders a single button. The button text is passed into the component like a standard HTML element, rather than through a prop. 

ui-ext-component-buttons-all

ui-extension-button-size-examples

href  string 

Navigates to a URL on button click. When a button includes both href and an onClick action, both will be executed on button click. Links to external pages will open in a new tab, while links to pages in the HubSpot account will open in the same tab.

onClick  function 

A function that will be invoked when the button is clicked. It receives no arguments and it's return value is ignored

disabled  boolean

Set to true to render the button in a disabled state.

variant  string 

Sets the color variation of the button. Values include:

  • primary
  • secondary (default)
  • destructive
size  string 

Sets the size of the button. Values include:

  • xs, extra-small
  • sm, small
  • md, medium (default)
type  string

Sets the HTML attribute role of the button. Can be one of:

  • button (default)
  • reset
  • submit
const Extension = () => { return ( <Button onClick={() => { console.log('Someone clicked the button!'); }} href="https://hubspot.com" variant="destructive" size="md" type="button" > Click me! </Button> ); };

Button row

The ButtonRow component renders a row of button components. In ButtonRow, you'll specify individual Button components.

ui-ext-component-buttonrow

disableDropdown  boolean 

Disables the dropdown list of buttons that appears when child button expand beyond horizontal space (false by default).

const Extension = () => { return ( <ButtonRow disableDropdown={false}> <Button onClick={() => { console.log('Regular button clicked'); }} > Regular Button </Button> <Button onClick={() => { console.log('Reset button clicked'); }} variant="destructive" type="reset" > Reset </Button> <Button onClick={() => { console.log('Submit button clicked'); }} variant="primary" type="submit" > Submit </Button> </ButtonRow> ); };

Description list

The DescriptionList component renders pairs of labels and values. It also contains a DescriptionListItem subcomponent.

ui-ext-component-descriptionlist

direction  string

The direction that the label and value pairs are displayed. By default, the value is set to column. You can also set the direction to row.

DescriptionListItem

label  string (required)

The text to display as the label.
const Extension = () => { return ( <DescriptionList direction="row"> <DescriptionListItem label={'First Name'}> <Text>Alan</Text> </DescriptionListItem> <DescriptionListItem label={'Last Name'}> <Text>Turing</Text> </DescriptionListItem> </DescriptionList> ); };

Divider

The Divider component renders a divider for spacing out components.

ui-ext-component-divider

distance  string

The space between the divider and the content above and below it. Can be one of:

  • extra-small
  • small (default)
  • medium
  • large
  • extra-large
  • flush
const Extension = () => { return <Divider distance="extra-large" />; };

ui-extensions-dropdown-variants

options  object (required)

The options included in the dropdown menu. For each option, include:

  • label: the text label for the option.
  • onClick: the function that gets invoked when the option is selected.
variant  string

The type of dropdown button to display. Values include:

  • primary (default): a blue button.
  • secondary: a grey button.
  • transparent: a hyperlink.
buttonText  string 

The text on the button.

buttonSize  string

The size of the button. Values include:

  • xs, extra-small
  • sm, small
  • md, medium
const Extension = () => { const ddOptions = [ { label: 'Clone', onClick: () => console.log({ message: 'Clone group' }) }, { label: 'Delete', onClick: () => console.log({ message: 'Delete group' }) } ] return ( <Dropdown options={ddOptions} variant="primary" buttonSize="md" buttonText="More" /> ); };

Empty state

The EmptyState component sets the content that appears when the extension is in an empty state.

ui-ext-components-emptystate

flush  boolean

When set to true, removes the default vertical margins in the component.

imageWidth  number

The max-width for the image container

layout  string

Sets the layout direction for the content. Can be either horizontal or vertical (default).

reverseOrder  boolean

When set to true, swaps the visual order of the text (primary) and image (secondary) content. This ensures the primary content is still presented first to assistive technology.

title  string

The text for the title header.

const Extension = ({ data }) => { if (!data || !data.length) { return ( <EmptyState title="Nothing here yet" layout="vertical" reverseOrder={true}> <Text>Go out there and get some leads!</Text> </EmptyState> ) } return ( {data.map(...)} ); }

Error state

The ErrorState component sets the content of an erroring extension.

ui-ext-components-errorstate

title  string 

The text of the title header.

type  string

The type of error image that will be shown. Can be one of:

  • error (default)
  • support
  • lock
const Extension = ({ data, error, fetchData }) => { if (error) { return ( <ErrorState title="Trouble fetching properties." layout="vertical" reverseOrder={true}> <Text> Please try again in a few moments. </Text> <Button onClick={fetchData}> Try again </Button> </ErrorState> ) } return ( {data.map(...)} ); }

Form

The Form component renders a form that can contain other subcomponents, such as Input, Select, and Button

ui-ext-components-form

onSubmit  function

The function that is called when the form is submitted. It will receive a RemoteEvent as an argument and its return value will be ignored.

preventDefault  boolean

When set to true, event.preventDefault() will be invoked before the onSubmit function is called, preventing the default HTML form behavior.

const Extension = () => { return ( <Form onSubmit={() => { console.log('Form submitted!')}} preventDefault={true}> <Input label="First Name" name="first-name" tooltip="Please enter your first name" description="Please enter your first name" placeholder="First name" /> <Input label="Last Name" name="last-name" tooltip="Please enter your last name" description="Please enter your last name" placeholder="Last name" /> <Button onClick={() => { console.log('Submit button clicked'); }} variant="primary" type="submit" > Submit </Button> </Form> ); }

Heading

The Heading component renders large heading text.

ui-ext-components-heading

inline  boolean 

When set to true, text will not line break.

const Extension = () => { return <Heading>Plain text, nothing special here</Heading>; };

Image

The Image component renders an image.

ui-ext-component-img

src  string (required)

The URL of the image to display.

alt  string 

The alt text for the image.

href  string 

If provided, will be used as the href that will be opened in a new browser tab on click.

onClick  function 

A function that will be called when the image is clicked. This function will receive no arguments and any returned values will be ignored.

width  number 

The pixel width of the image.

height  number 

The pixel height of the image.

const Extension = () => { return ( <Image alt="A picture of an adorable black lab puppy, click on me to see in a new tab" src="https://picsum.photos/id/237/200/300" href="https://picsum.photos/id/237" onClick={() => { console.log('Someone clicked on the image!'); }} width={200} /> ); };

Checkbox

The Checkbox component renders single checkbox input. If you want to display multiple checkboxes, you may want to use ToggleGroup instead, as it comes with extra logic for handling multiple checkboxes and radio buttons.

ui-extensions-component-checkbox

value  string

The checkbox value. This value is not displayed on the card, but is passed on the server side when submitted, along with the checkbox name.

name  string

The checkbox's unique identifier.

checked  boolean 

When set to true, the checkbox is selected by default. Default is false.

initialIsChecked  boolean 

When set to true, the checkbox is selected by default. Default is false.

readonly  boolean 

When set to true, users cannot toggle the checkbox. Default is false.

description  string 

The string that displays below the checkbox.

aira-label  string

The checkbox's accessibility label.

variant  string 

The size of the checkbox. Values include:

  • sm, small
  • default
inline  boolean

When set to true, arranges checkboxes side by side. Default is false.

onChange  function

A callback function that is called when the checkbox is selected or cleared. Passes the new value.

(checked: boolean, value: string) => void;

const Extension = () => { return ( <Checkbox checked={isSuperAdmin} name="adminCheck" description="Select to grant superpowers" > Super Admin </Checkbox> ); };

Date input

The DateInput component renders an input field where a user can select a date.

ui-extension-components-date-input

name  string (required)

The input's unique identifier, similar to the HTML input element name attribute.

label  string (required)

The text that displays above the input.

required  boolean 

When set to true, displays a required indicator.

value  object 

The value of the input. Must include the year, month, and day:

{ year: number;month: number;date: number }

  • year: the four-digit year (e.g., 2023).
  • month: starting at 0, the number of the month (e.g., 0 = January, 11 = December).
  • date: the number of the day (e.g., 1 = the first day of the month).
readOnly  boolean 

When set to true, sets the field as read-only on the CRM record, and users will not be able to fill the field.

description  string 

Displayed text that describes the field's purpose.

tooltip  string 

The text that displays in a tooltip next to the label.

error  boolean

When set to true, validationMessage is displayed as an error message if provided. The input will also render its error state to let the user know there's an error. If left false (default), validationMessage is displayed as a success message.

validationMessage  string 

The text to show if the input has an error.

onChange  function

A callback function that is invoked when the value is committed. Will not get called on invalid inputs.

onBlur  function 

A function that is called and passes the value when the field loses focus.

onFocus  function 

A function that is called and passed the value when the field gets focused.

min  object 

Sets the earliest valid date available using the following format:

{ year: number;month: number;date: number }

  • year: the four-digit year (e.g., 2023).
  • month: starting at 0, the number of the month (e.g., 0 = January, 11 = December).
  • date: the number of the day (e.g., 1 = the first day of the month).
max  object 

A Sets the latest valid date available using the following format:

{ year: number;month: number;date: number }

  • year: the four-digit year (e.g., 2023).
  • month: starting at 0, the number of the month (e.g., 0 = January, 11 = December).
  • date: the number of the day (e.g., 1 = the first day of the month).
minValidationMessage  string 

A function that is called and passed the value when the field gets focused.

maxValidationMessage  string 

A function that is called and passed the value when the field gets focused.

format  string 

Sets the date format the input will display. Can be one of:

  • short (default): 09/04/1986
  • long: September 4, 1986
  • medium: Sep 4, 1986
  • standard: 1986-09-04
  • YYYY-MM-DD: 1986-09-04
  • L: 09/04/1986
  • LL: September 4, 1986
  • ll: Sep 4, 1986
timezone  string 

Sets the timezone that the component will use to calculate valid dates. Can be one of:

  • userTz (default): the user's time zone.
  • portalTz: the portal's default time zone.
clearButtonLabel  string 

Sets the label of the button to clear the selected date. Clear by default.

todayButtonLabel  string 

Sets the label of the button to select today's date. Today by default.

function RemoteApp() { const [dateValue, setDateValue] = useState(null); return ( <Flex direction="column"> <DateInput label="Appointment Date Partially Controlled" name="date" onChange={(value) => { setDateValue(value); }} value={dateValue} format="ll" /> <DateInput label="Appointment Date Uncontrolled" name="appointment-date" format="LL" /> </Flex> ); }

Input

The Input component renders a text input field where a user can enter a custom text value.

ui-extension-component-input-with-typed-password

name  string (required)

The input's unique identifier, similar to the HTML input element name attribute.

label  string (required)

The text that displays above the input. Required if inputType is not set to hidden.

required  boolean 

When set to true, displays a required indicator.

value  string 

The value of the input.

type  string 

The type of input. Can be either text (default) or password. An input with the password type will hide the characters that the user types.

readOnly  boolean 

When set to true, sets the field as read-only on the CRM record, and users will not be able to fill the input field.

description  string 

Displayed text that describes the field's purpose.

tooltip  string 

The text that displays in a tooltip next to the label.

placeholder  string 

Text that appears in the input when no value is set.

error  boolean

When set to true, validationMessage is displayed as an error message if provided. The input will also render its error state to let the user know there's an error. If left false (default), validationMessage is displayed as a success message.

validationMessage  string 

The text to show if the input has an error.

onChange  function

A callback function that is invoked when the value is committed. Currently, these are onBlur of the input and when the user submits the form.

onInput  function (required)

A function that is called and passes the value when the field is edited by the user. Should be used for validation. It's recommended that you don't use this value to update state (use onChange instead).

onBlur  function 

A function that is called and passes the value when the field loses focus.

onFocus  function 

A function that is called and passed the value when the field gets focused.

import { useState } from 'react'; const Extension = () => { const [name, setName] = useState(''); const [validationMessage, setValidationMessage] = useState(''); const [isValid, setIsValid] = useState(true); return ( <Form> <Input label="First Name" name="first-name" tooltip="Please enter your first name" description="Please enter your first name" placeholder="First name" required={true} error={!isValid} validationMessage={validationMessage} onChange={value => { setName(value); }} onInput={value => { if (value !== 'Bill') { setValidationMessage('This form only works for people named Bill'); setIsValid(false); } else if (value === '') { setValidationMessage('First name is required'); setIsValid(false); } else { setValidationMessage('Valid first name!'); setIsValid(true); } }} /> <Input label="Password" name="password" description="Enter your password" placeholder="Password" onInput={() => {}} type="password" /> </Form> ); };

Multi-select input

The MultiSelect component renders a dropdown menu select field where a user can select multiple values. Commonly used within the Form component. 

ui-extensions-component-multiselect

label  string (required)

The text that displays above to the dropdown menu.

name  string (required)

The unique identifier for the select element.

value  array

The value of the select input.

options  array (required)

The options to display in the dropdown menu. label will be used as the display text, and value should be the option's unique identifier, which is submitted with the form.

required  boolean 

When set to true, displays a required field indicator.

readOnly  boolean 

When set to true, sets the field as read-only on the CRM record, and users will not be able to fill the input field.

description  string 

Displayed text that describes the field's purpose.

tooltip  string 

The text that displays in a tooltip next to the label.

placeholder  string 

Text that appears in the input when no value is set.

error  boolean

When set to true, validationMessage is displayed as an error message if provided. The input will also render its error state to let the user know there's an error. If left false (default), validationMessage is displayed as a success message.

validationMessage  string 

The text to show if the input has an error.

onChange  function

A callback function that is invoked when the value is committed. 

function MultiSelectControlledExample() { const [formValue, setFormValue] = useState([]); return ( <Form preventDefault={true} onSubmit={() => console.log(formValue, 'hola')}> <MultiSelect value={formValue} placeholder="Pick your Products" label="Select Mutiple Products" name="selectProduct" required={true} onChange={(value) => setFormValue(value)} options={[ { label: 'Amazing Product 1', value: 'p1' }, { label: 'Amazing Product 2', value: 'p2' }, { label: 'Amazing Product 3', value: 'p3' }, { label: 'Amazing Product 4', value: 'p4' }, { label: 'Amazing Product 5', value: 'p5' }, { label: 'Amazing Product 6', value: 'p6' }, ]} /> <Button type="submit">Submit</Button> </Form> ); }

Number input

The NumberInput component renders a number input field.

ui-ext-numberinput

name  string (required)

The input's unique identifier, similar to the HTML input element name attribute.

label  string (required)

The text that displays above the input. Required if inputType is not set to hidden.

required  boolean 

When set to true, displays a required indicator.

value  string 

The value of the input.

readOnly  boolean 

When set to true, sets the field as read-only on the CRM record, and users will not be able to fill the input field.

description  string 

Displayed text that describes the field's purpose.

tooltip  string 

The text that displays in a tooltip next to the label.

placeholder  string 

Text that appears in the input when no value is set.

error  boolean

When set to true, validationMessage is displayed as an error message if provided. The input will also render its error state to let the user know there's an error. If left false (default), validationMessage is displayed as a success message.

validationMessage  string 

The text to show if the input has an error.

onChange  function

A callback function that is invoked whenever a valid number is entered. The function is invoked with the current numerical value of the input.

Entering a non-numerical character will not invoke the function. But following that character with a valid number will call the function with the field's current numerical value without the invalid character. For example, entering 1d4 as separate characters will result in the following:

  • After entering 1: the function is invoked with 1.
  • After entering d: the function is not invoked.
  • After entering 4: the function is invoked with 14.
onBlur  function 

A function that is called and passes the value when the field loses focus.

onFocus  function 

A function that is called and passed the value when the field gets focused.

min  number 

Sets the lower bound of the input.

max  number 

Sets the upper bound of the input.

precision  number 

Sets the number of digits to the right of the decimal point.

formatStyle  string 

Formats the input as a decimal point (decimal) or percentage (percentage).

const Extension = () => { const [portalCount, setPortalCount] = useState(0); return ( <NumberInput label={'HubSpot Portal Count'} name="portalsNumber" description={'Number of active portals'} placeholder={'number of portals'} value={portalCount} onChange={value => setPortalCount(value)} /> ); };

Radio button

The RadioButton component renders a radio select button. If you want to include more than two radio buttons, or are building a form, it's recommended to use the ToggleGroup component instead.

ui-extensions-component-radio-buttons

value  string

The radio button value. This value is not displayed, but is passed on the server side when submitted, along with the checkbox name.

name  string

The radio button's unique identifier.

checked  boolean 

When set to true, the radio button is selected by default. Default is false.

initialIsChecked  boolean 

When set to true, the radio button is selected by default. Default is false.

readonly  boolean 

When set to true, users cannot select the radio button. Default is false.

description  string 

The string that displays below the radio button.

variant  string 

The size of the checkbox. Values include:

  • sm, small
  • default
inline  boolean

When set to true, arranges radio buttons side by side. Default is false.

onChange  function

A callback function that is called when the radio button is selected. Passes the new value.

(checked: boolean, value: string) => void;

function Extension() { const [roleType, setRoleType] = useState( 'support' ); return ( <> <RadioButton checked={roleType === 'superAdmin'} name="roleType" description="Select to grant superpowers." onChange={() => { setRoleType('superAdmin'); }} > Super Admin </RadioButton> <RadioButton checked={roleType === 'support'} name="roleType" description="Select to assign a Support role." onChange={() => { setRoleType('support'); }} > Customer Support </RadioButton> </> ); }

Select input

The Select component renders a dropdown select input field where a user can select a single value. When there are more than seven selectable options in the input, the component will automatically include a search field. Commonly used within the Form component. 

Using the variant prop, you can render the input with standard styling or transparent styling:

  • variant="input" (default):
    ui-extension-components-input-selelect-input-variant
  • variant="transparent"

ui-extension-components-input-selelect-transparent-variant

name  string (required)

The input's unique identifier, similar to the HTML input element name attribute.

label  string (required)

The text that displays above the input. Required if inputType is not set to hidden.

required  boolean 

When set to true, displays a required indicator.

value  string 

The value of the input.

readOnly  boolean 

When set to true, sets the field as read-only on the CRM record, and users will not be able to fill the input field.

description  string 

Displayed text that describes the field's purpose.

tooltip  string 

The text that displays in a tooltip next to the label.

placeholder  string 

Text that appears in the input when no value is set.

error  boolean

When set to true, validationMessage is displayed as an error message if provided. The input will also render its error state to let the user know there's an error. If left false (default), validationMessage is displayed as a success message.

validationMessage  string 

The text to show if the input has an error.

onChange  function

A callback function that is invoked when the value is committed. Currently, these are onBlur of the input and when the user submits the form.

options  array

An array of options to display in the dropdown menu. Each object in the array contains:

  • label: the text that displays in the dropdown menu.
  • value: the unique value that is submitted with the form.
variant  string

The type of input, which controls its appearance. Values include:

  • input (default): the standard select input, including a grey background and border.
  • transparent: removes the background and border from the input. The input will render as a blue hyperlink with an arrow.
const Extension = () => { const [name, setName] = useState(null); const [validationMessage, setValidationMessage] = useState(''); const [isValid, setIsValid] = useState(true); const options = [ { label: 'Bill', value: 42 }, { label: 'Ted', value: 43 }, ]; return ( <Form> <Select label="Best Bill & Ted Character?" name="best-char" tooltip="Please choose" description="Please choose" placeholder="Bill or Ted?" required={true} error={!isValid} validationMessage={validationMessage} onChange={value => { setName(value); if (!value) { setValidationMessage('This is required'); setIsValid(false); } else { setValidationMessage('Excellent!'); setIsValid(true); } }} options={options} /> </Form> ); };

Stepper input

The StepperInput component renders a number input field that can be increased or decreased by a set number. This component inherits many of its props from the NumberInput component, with an additional set of props to control the increase/decrease interval.

ui-extension-component-stepper-input

name  string (required)

The input's unique identifier, similar to the HTML input element name attribute.

label  string (required)

The text that displays above the input. Required if inputType is not set to hidden.

stepSize  number

The amount that the current value will increase or decrease by. By default, set to 1.

maxValueReachedTooltip  string 

When the maximum value (max) has been reached, this text will display in a tooltip when hovering over the increase button. 

minValueReachedTooltip  string

When the minimum value (min) has been reached, this text will display in a tooltip when hovering over the increase button.

min  number 

Sets the lower bound of the input.

max  number 

Sets the upper bound of the input.

required  boolean 

When set to true, displays a required indicator.

value  string 

The value of the input.

readOnly  boolean 

When set to true, sets the field as read-only on the CRM record, and users will not be able to fill the input field.

description  string 

Displayed text that describes the field's purpose.

tooltip  string 

The text that displays in a tooltip next to the label.

placeholder  string 

Text that appears in the input when no value is set.

error  boolean

When set to true, validationMessage is displayed as an error message if provided. The input will also render its error state to let the user know there's an error. If left false (default), validationMessage is displayed as a success message.

validationMessage  string 

The text to show if the input has an error.

onChange  (value: number) => void;

A callback function that is invoked whenever a valid number is entered. The function is invoked with the current numerical value of the input.

Entering a non-numerical character will not invoke the function. But following that character with a valid number will call the function with the field's current numerical value without the invalid character. For example, entering 1d4 as separate characters will result in the following:

  • After entering 1: the function is invoked with 1.
  • After entering d: the function is not invoked.
  • After entering 4: the function is invoked with 14.
onBlur  (value: number) => void;

A function that is called and passes the value when the field loses focus.

onFocus  (value: number) => void; 

A function that is called and passed the value when the field gets focused.

precision  number 

Sets the number of digits to the right of the decimal point.

formatStyle  string 

Formats the input as a decimal point (decimal) or percentage (percentage).

return ( <StepperInput min={5} max={20} minValueReachedTooltip="You need to eat at least 5 cookies." maxValueReachedTooltip="More than 20 cookies is a bit much." label="Number of cookies to eat" name="cookiesField" description={'I want cookies'} value={cookies} stepSize={5} onChange={(value) => { setCookieCount(value); }} /> );

Text area input

The TextArea component renders a fillable text field. You can customize the size of the field along with maximum number of characters and resizability.

ui-ext-components-textarea

name  string (required)

The input's unique identifier, similar to the HTML input element name attribute.

label  string (required)

The text that displays above the input. Required if inputType is not set to hidden.

required  boolean 

When set to true, displays a required indicator.

value  string 

The value of the input.

readOnly  boolean 

When set to true, sets the field as read-only on the CRM record, and users will not be able to fill the input field.

description  string 

Displayed text that describes the field's purpose.

tooltip  string 

The text that displays in a tooltip next to the label.

placeholder  string 

Text that appears in the input when no value is set.

error  boolean

When set to true, validationMessage is displayed as an error message if provided. The input will also render its error state to let the user know there's an error. If left false (default), validationMessage is displayed as a success message.

validationMessage  string 

The text to show if the input has an error.

onChange  function

A callback function that is invoked when the value is committed. Currently, these are onBlur of the input and when the user submits the form.

onInput  function (required)

A function that is called and passes the value when the field is edited by the user. Should be used for validation. It's recommended that you don't use this value to update state (use onChange instead).

onBlur  function 

A function that is called and passes the value when the field loses focus.

onFocus  function 

A function that is called and passed the value when the field gets focused.

cols  number 

The visible width of the text field in average character widths.

rows  number 

The number of visible text lines for the text field.

maxLength  number 

The maximum number of characters (UTF-16 code units) that the user can enter. If not specified, the max length is unlimited.

resize  string 

Sets whether the element is resizable, and if so in which directions. Can be one of:

  • vertical
  • horizontal
  • both
  • none
import { useState } from 'react'; const Extension = () => { const [description, setDescription] = useState(''); const [validationMessage, setValidationMessage] = useState(''); const [isValid, setIsValid] = useState(true); return ( <Form> <TextArea label="Description" name="description" tooltip="Provide as much detail as possible" description="Please include a link" placeholder="My description" required={true} error={!isValid} validationMessage={validationMessage} onChange={value => { setDescription(value); }} onInput={value => { if (!value.includes('http')) { setValidationMessage('A link must be included.'); setIsValid(false); } else { setValidationMessage('Valid description!'); setIsValid(true); } }} /> </Form> ); };

Toggle

The Toggle component renders a boolean toggle switch that can be configured with sizing, label position, read-only, and more.

ui-extension-toggle

label  string (required)

The toggle's label. By default, the label will display inline to the left of the switch. You can use the labelDisplay prop to further configure the label.

labelDisplay  string 

The display option for the toggle label. Values include:

  • inline (default): the label appears inline to the left of the switch.
  • top: the label appears above the switch.
  • hidden: the label is hidden.
checked  boolean 

When set to true, the toggle is checked and displays a blue enabled state. Default is false.

readonly  boolean 

When set to true, the toggle is set to read-only, appearing greyed out and unable to be interacted with by users.

name  string 

The internal name of the toggle.

size  string 

The size of the toggle. Values include:

  • xs, extra-small
  • sm, small
  • md, medium (default)

Note that only md/ medium sized toggles can display text on the toggle (ONOFF). All other sizes will hide checked/unchecked text.

onChange  (checked: boolean) => void;
 
A function that is invoked when the toggle is clicked.
initialIsChecked  boolean 

When set to true, the toggle is checked by default. Default is false.

textChecked  string 

The text that displays on the toggle when checked. Default is ON. Extra small and small toggles will not display any text.

textUnchecked  string 

The text that displays on the toggle when not checked. Default is OFF. Extra small and small toggles will not display any text.

const Extension = () => { return ( <Toggle size="sm" label="My toggle" labelDisplay="top" initialIsChecked={true} /> ); };

Toggle group

The ToggleGroup component renders a list of selectable options.

ui-ext-components-togglegroup

name  string (required)

The unique identifier for the toggle group element.

label  string (required)

The label that displays above the toggle group.

toggleType  string (required)

The type of toggle group. Can be one of:

  • radioButtonList: options will render as radio buttons. Only allows for one option to be selected.
  • checkboxList: options will render as checkboxes. Allows for multiple options to be selected.
error  boolean

When set to true, validationMessage is displayed as an error message if provided. The input will also render its error state to let the user know there is an error. If left false, validationMessage is displayed as a success message.

options  array (required)

An array of options to display in the dropdown menu. Each object in the array contains:

  • label (string): the text that displays next to the checkbox.
  • value (string): the unique value that is submitted with the form.
  • initialIsChecked (boolean): when set to true, the option will be selected by default.
  • readonly (boolean): when set to true, the option cannot be selected.
  • description: the string that displays below the toggle.
value  string 

The value of the toggle group.

  • If toggleType is radioButtonList, this should be a string.
  • If toggleType is checkboxList, this should be an array of strings.
onChange  function (required)

A function that is called with the new value or values when it's updated.

  • If toggleType is radioButtonList, the function will be called with the value that is a string.
  • If toggleType is checkboxList, the function will be called with the value that is an array of strings.
required  boolean 

When set to true, displays a required indicator next to the toggle group.

tooltip  string 

Text that will appear in a tooltip next to the toggle group label.

validationMessage  string

The text to display if the input has an error.

inline  boolean

When set to true, stacks the options horizontally.

variant  string 

The size variation of the individual options. Can be one of default (default) or small.

const options = [1, 2, 3, 4].map(n => ({ label: `Option ${n}`, value: `${n}`, initialIsChecked: n === 2, readonly: false, description: `This is option ${n}`, })); const Extension = () => { return ( <ToggleGroup name="toggle-checkboxes" label="Toggle these things" error={false} options={options} tooltip="Here's a secret tip." validationMessage="Make sure you do the thing correctly." required={false} inline={false} toggleType="checkboxList" variant="default" /> ); };

The Link component renders a clickable hyperlink.

ui-ext-components-link

href  string

The URL that will be opened on click. Links to pages in the HubSpot account will open in the same tab, while non-HubSpot links will open in a new tab.

variant  string 

The color variation of the link. Can be one of:

  • primary (default)
  • light
  • dark
  • destructive
onClick  function

A function that will be invoked with the link is clicked. The function receives no arguments and its return value is ignored.

preventDefault  boolean

When set to true, event.preventDefault() will be invoked before the onClick function is called, preventing automatic navigation to the href URL.

const Extension = () => { return <Link href="https://app.hubspot.com/">HubSpot</Link>; };

List

The List component renders a list of items. Each item in List will be wrapped in <li> tags. A list can be styled as inline, ordered, or unordered with the variant prop.

ui-extension-component-list

variant  string

The type of list to render.

  • unordered (default): an unordered list without bullet points.
  • unordered-styled: an unordered list with bullet points.
  • ordered: an ordered list without numbers.
  • ordered-styled: an unordered list without numbers.
  • inline: an inline list (items are on one line).
  • inline-divided: an inline list with vertical dividers between each item.
const Extension() { return ( <List variant="unordered-styled"> <Link href="www.hubspot.com">List item 1</Link> <Link href="www.developers.hubspot.com">List item 2</Link> <Link href="www.knowledge.hubspot.com">List item 3</Link> </List> ); }

Layout: Flex

The Flex component renders an empty div container set to display=flex. When wrapped around other components, this enables those child components to be arranged using props. Flex can contain other Flex or Box components. Learn more about configuring UI extension layout.

ui-extension-components-flex-child

direction  string

Arranges components horizontally or vertically by setting the main axis. Can be one of:

  • row (default)
  • column
justify  string 

Distributes components along the main axis using the available free space. Can be one of:

  • center
  • start (default)
  • end
  • around
  • between
align  string 

Distributes components along the cross-axis using the available free space. Can be one of:

  • start
  • center
  • baseline
  • end
  • stretch (default)
alignSelf  string 

Distributes a child component along the cross-axis using the available free space. Use this prop for nested child Flex and Box components to align them differently from other child components in the Flex group. Can be one of:

  • start
  • center
  • baseline
  • end
  • stretch
wrap  string 

Whether components will wrap instead of trying to fit on one line. Can be one of:

  • wrap
  • nowrap
gap  string 

Sets the spacing between components. Can be one of: 

  • flush (default)
  • extra-small
  • small
  • medium
  • large
  • extra-large
const Extension = () => { return ( <Flex direction={'row'} justify={'end'} wrap={'wrap'} gap={'small'} > <Tile>Left</Tile> <Tile>Right</Tile> <Flex direction={'column'}> <Tile>Bottom</Tile> </Flex> </Flex> ); };

Layout: Box

The Box component renders an empty div container, and can be wrapped around Flex child components. Use this component to fine tune spacing of individual components. Learn more about configuring UI extension layout.

ui-extrensions-layout-box

alignSelf  string 

Distributes a child component along the cross-axis using the available free space. Use this prop for nested child Box components to align them differently from other child components in the Flex group. Can be one of:

  • start
  • center
  • baseline
  • end
  • stretch
flex  string 

Distributes components based on the available empty space around them. Can be one of:

  • number value
  • initial (default)
  • auto
  • none
const Extension = () => { return ( <Flex direction={'row'} justify={'start'} gap={'small'} > <Box flex={1}> <Tile>flex = 1</Tile> </Box> <Box flex={2}> <Tile>flex = 2</Tile> </Box> <Box flex={3}> <Tile>flex = 3</Tile> </Box> <Box flex={4}> <Tile>flex = 4</Tile> </Box> </Flex> ); };

Loading spinner

The LoadingSpinner component renders a spinner that indicates a loading state.

2023-05-26_13-38-56 (1)

 

label  string

The text that displays next to the spinner.

showLabel  boolean 

When set to true, the label will appear next to the spinner. Value is false by default.

size  string 

The size of the spinner. Can be one of:

  • xs
  • sm (default)
  • md
layout  string 

The position of the spinner. Can be one of inline or centered.

const Extension = () => { return ( <LoadingSpinner label="Loading..." /> ); };

Panel

The Panel component renders a panel on the right side of the CRM record and contains other components. The panel can be opened and closed by using onClick handles for Button, Link, Tag, and Image components. Learn more about how to open a panel in your UI extension. To see an example of incorporating a panel into an extension, check out HubSpot's Build a multi-step flow sample project.

panel-example-gif

The Panel component uses three subcomponents to control its design and content, which follows the general structure below:

  • <Panel>: the outermost container.  
    • <PanelBody>: the container that wraps the panel's content and makes it scrollable. Include only one PanelBody per Panel.
      • <PanelSection>: a container that adds padding and bottom margin to provide spacing between content. You can use Flex and Box to further customize content layout.
    • <PanelFooter>: a sticky footer component at the bottom of the panel. Include only one PanelFooter per Panel.

Please note:

  • Panels must be a top-level component. They cannot be contained within other components, such as Flex.
  • Only one panel can be open at a time. Opening a panel while another is already open will cause the first panel to close.
  • If your onClick function to open the panel is asynchronous, ensure that it returns a promise.

<Panel> props

id  string (required)

A unique ID for the panel.

onOpen  () => void; 

A function that will be invoked when the panel has finished opening.

onClose  () => void;

A function that will be invoked with the panel has finished closing.

width  string 

The width of the panel. Can be one of:

  • sm, small (default)
  • md, medium
  • lg, large
title  string 

The title that displays at the top of the panel.

variant  'modal'  | 'default'

The variant of the panel. The modal variant includes better screen reader focus on the panel and is recommended for visual and motor accessibility and tab navigation.

aria-label  string

The panel's accessibility label.

<PanelSection> props

flush  boolean 

When set to true, the section will have no bottom margin. Default is false.

<> <Panel title="Welcome to my Panel" id="my-panel"> <Form> <PanelBody> <PanelSection> <Select name="test" label="Test" options={[ {label: 'foo', value: 'foo'}, {label:"bar", value: "bar"}]} /> </PanelSection> <PanelSection> lorem ipsum... </PanelSection> </PanelBody> <PanelFooter><Button type="submit">Click me</Button></PanelFooter> </Form> </Panel> <Button onClick={(event, reactions) => { reactions.openPanel('my-panel')}}> Open Panel </Button> </>

Progress bar

The ProgressBar component renders a progress bar that shows a numeric and/or percentage-based representation of progress. HubSpot calculates the percent based on the maximum possible value specified in the component.ui-ext-components-progressbar-description

title  string

The text that displays above the progress bar.

showPercentage  boolean 

Whether the progress bar displays the completion percentage.

value  number 

The number representing the progress so far. Defaults to 0.

maxValue  number 

The maximum value of the progress bar. Defaults to 100.

valueDescription  string 

The text that explains the current state of the value property. For example, "150 out of 250". Displays above the progress bar on the right side.

variant  string

The color that indicates the type of progress bar. Can be one:

  • success
  • danger
  • warning
const Extension = () => { return ( <ProgressBar variant="warning" value={50} maxValue={200} showPercentage={true} /> ); };

Statistics

The Statistics component renders data summaries via the StatisticsItem and StatisticsTrend child components.

ui-ext-components-statistics

StatisticsItem

id  string

The unique identifier

label  string

The item's label text.

number  string

The string to be displayed as the item's primary number.

StatisticsTrend

value  string

The text to be displayed as the trend value.

direction  string

The direction of the trend arrow. Can be one of increase or decrease.

const Extension = () => { return ( <Statistics> <StatisticsItem label="Item A Sales" number="10000"> <StatisticsTrend direction="decrease" value="200%" /> </StatisticsItem> <StatisticsItem label="Item B Sales" number="100000"> <StatisticsTrend direction="increase" value="100%" /> </StatisticsItem> </Statistics> ); };

Step indicator

The StepIndicator component renders a horizontal indicator to show the current step of a multi-step process.

ui-extension-component-stepindicator

stepNames  array (required)

An array containing the name of each step.

currentStep  number

The currently active step.

direction  string

The orientation of the indicator. Can be one of horizontal or vertical.

onClick  function

A function that will be invoked when a step in the indicator is clicked. The function receives the current step index as an argument (zero-based). Use this to update the currently active step.

circleSize  string

The size of the indicator circles. Can be one of:

  • extra-small
  • small (default)
  • medium
  • large
  • extra-large
variant  string

The visual style of the component. Can be one of:

  • default: default spacing.
  • compact: only shows the title of the currently active step.
  • flush: only shows the title of the currently active step and removes left and right margins.
function Extension() { const [currentStep, setCurrentStep] = useState(0); return ( <StepIndicator currentStep={currentStep} stepNames={["First", "Second", "Third"]} /> <Button onClick={() => setCurrentStep(currentStep - 1)}> Previous </Button> <Button onClick={() => setCurrentStep(currentStep + 1)}>Next</Button> ); }

Table

The Table component renders a table. To format the table, you can use the following subcomponents:

  • TableHead: the header section of the table containing column labels.
  • TableRow: individual table rows.
  • TableHeader: cells containing bolded column labels. Use the sortDirection and onSortChange props to make the table sortable.
  • TableBody: container for the main table contents (rows and cells).
  • TableCell: individual cells within the main body.

You can also configure pagination with the pagination prop.

design-guidelines-table-paginated

flush  boolean 

When set to true, the table will not have bottom margin.

bordered  boolean 

When set to false, the table will not have borders.

paginated  boolean 

When set to true, the table will include pagination navigation. To configure pagination options, you'll need to configure the following pagination props:

pageCount  string

The total number of pages available.

onPageChange  function

A function that will be invoked when the pagination button is clicked. It receives the new page number as argument.

onPageChange: (pageNumber: number) => void

showButtonLabels  boolean

When set to false, hides the text labels for the First/Prev/Next buttons. The button labels will still be accessible to screen readers.

showFirstLastButtons  boolean

When set to true, displays the First/Last page buttons

maxVisiblePageButtons  number

Sets how many page buttons are displayed.

page  number

Denotes the current page.

align  string

Align TableCell and TableHeader subcomponents using left, center, or right.

width  string

Set the width of TableCell and TableHeader subcomponents with a specific pixel value or one of the following values:

  • min: the content will only be as wide as required, overflowing if the content is wider than the table. A horizontal scrollbar will appear when there is overflow.
  • max: the content will expand to occupy the maximum available width without overflowing.
  • auto: the content will adjust its width based on the available space without overflowing.

 

const Extension = () => { return ( <Table bordered={true} paginated={true} pageCount="5" > <TableHead> <TableRow> <TableHeader>Name</TableHeader> <TableHeader>Role</TableHeader> </TableRow> </TableHead> <TableBody> <TableRow> <TableCell>Tim Robinson</TableCell> <TableCell>Driver's Ed. Instructor</TableCell> </TableRow> <TableRow> <TableCell>Patti Harrison</TableCell> <TableCell>Tables (vendor)</TableCell> </TableRow> <TableRow> <TableCell>Sam Richardson</TableCell> <TableCell>Show host</TableCell> </TableRow> <TableRow> <TableCell>Ruben Rabasa</TableCell> <TableCell>Car imagineer</TableCell> </TableRow> </TableBody> </Table> ); }

Sortable tables

To add sorting functionality to a table, you can include the sortDirection and onSortChange props in the table's TableHeader components. To enable table data to dynamically reorder based on user input, you'll need to store your table data in variables rather than hard coding it into table cells. Below is an example of a sortable table with a static table footer.

ui-extensions-sortable-table-1

sortDirection  string 

Visually indicates with an arrow which way the rows are sorted. Values include:

  • none (default)
  • ascending
  • descending
onSortChange  function 

A function that will be invoked when the header is clicked. It receives a sortDirection as an argument (cannot be none or a null value).

hubspot.extend(({ context, runServerlessFunction, actions }) => ( <Extension context={context} runServerless={runServerlessFunction} sendAlert={actions.addAlert} /> )); const ORIGINAL_DATA = [ { name: 'The Simpsons', yearsOnAir: 28, emmys: 31, }, { name: 'M*A*S*H', yearsOnAir: 11, emmys: 14, }, { name: 'Arrested Development', yearsOnAir: 4, emmys: 5, }, ]; const DEFAULT_STATE = { name: 'none', yearsOnAir: 'none', emmys: 'none', } function Extension() { const [data, setData] = useState(ORIGINAL_DATA); const [sortState, setSortState] = useState({...DEFAULT_STATE}); function handleOnSort(fieldName, sortDirection) { const dataClone = [...data]; dataClone.sort((entry1, entry2) => { if (sortDirection === 'ascending') { return entry1[fieldName] < entry2[fieldName] ? -1 : 1; } return entry2[fieldName] < entry1[fieldName] ? -1 : 1; }); setSortState({ ...DEFAULT_STATE, [fieldName]: sortDirection }); setData(dataClone); } return ( <Table> <TableHead> <TableRow> <TableHeader sortDirection={sortState.name} onSortChange={sortDirection => handleOnSort('name', sortDirection)} > Series </TableHeader> <TableHeader sortDirection={sortState.yearsOnAir} onSortChange={sortDirection => handleOnSort('yearsOnAir', sortDirection) } > Years on air </TableHeader> <TableHeader sortDirection={sortState.emmys} onSortChange={sortDirection => handleOnSort('emmys', sortDirection)} > Emmys </TableHeader> </TableRow> </TableHead> <TableBody> {data.map(({ name, yearsOnAir, emmys }) => { return ( <TableRow key={name}> <TableCell>{name}</TableCell> <TableCell>{yearsOnAir}</TableCell> <TableCell>{emmys}</TableCell> </TableRow> ); })} </TableBody> <TableFooter> <TableRow> <TableHeader>Totals</TableHeader> <TableHeader>43</TableHeader> <TableHeader>50</TableHeader> </TableRow> </TableFooter> </Table> ); }

Tag  

The Tag component renders a tag.

ui-ext-components-tag

onClick  function

A function that will be invoked when the tag is clicked. It receives no argument and its return value is ignored.

variant  string

The tag's color. The following variants are available: default (default), warning, success, and error.

const Extension = () => { return ( <Tag variant='success' onClick={() => { console.log('Tag clicked!'); }} > Success </Tag> ); }

Text

The Text component renders text with formatting options.

ui-extension-text-component-with-truncate

format  object (required)

The type of formatting for the text. Format types include:

  • { fontWeight: 'bold' }
  • { fontWeight: 'demibold' }
  • { italic: true }
  • { lineDecoration: 'strikethrough' }
  • { lineDecoration: 'underline' }
variant string

The style of text to display. Can be either of:

  • bodytext: the default value which renders the standard text size.
  • microcopy: smaller text used for adding context.
inline boolean

When set to false, inserts a line break. 

truncate boolean | object

This prop takes either a boolean or an options object:

  • false (default): text is not truncated.
  • true: truncates text to a single line. Full text will display in a tooltip on hover.

To specify the maximum width of the text and the text that will appear in a tooltip on hover:

truncate={{ tooltipText: 'string', maxWidth: px }}

  • {tooltipText: 'string'}: sets the text that will display in a tooltip on hover.
  • {maxWidth: px}: the number of pixels wide to set the text before truncating.
const Extension = () => { return ( <> <Text truncate={{ tooltipText:'string', maxWidth: 68 }}>Truncated text</Text> <Text>Plain text</Text> <Text format={{ fontWeight: 'bold' }}>Bold</Text> <Text format={{ italic: true }}>Italics</Text> <Text format={{ fontWeight: 'bold', italic: true }}> Bold and Italic text </Text> <Text format={{ lineDecoration: 'strikethrough' }}> Strikethrough Text </Text> <Text variant="microcopy"> Microcopy text <Text inline={true} format={{ fontWeight: 'bold' }}> with inner bold </Text> </Text> </> ); };

Tile

The Tile component renders a square tile containing other components.

ui-ext-components-tile

flush  boolean 

When set to true, removes left and right padding from tile contents.

const Extension = () => { return ( <> <Tile flush={true}> <Text>No left padding</Text> </Tile> <Tile> <Text>Small amount of left padding</Text> </Tile> </> ); };

CRM data components

CRM data components can pull data directly from the currently displaying CRM record, including information about associated records and single object reports. These components can only be placed in the middle column of CRM records.

These components are imported from @hubspot/ui-extensions/crm.

import { CrmAssociationPivot, CrmReport } from '@hubspot/ui-extensions/crm';

In the CrmAssociationPivot and CrmAssociationTable components, you can filter the data to fetch only what's most relevant. Review the table below for available filtering options.

Use this table to describe parameters / fields
PropTypeDescription
operator
String

The filter's operator (e.g. IN). Can be one of:

  • EQ: is equal to value.
  • NEQ: is not equal to value.
  • LT: is less than value.
  • LTE:  is less than or equal to value.
  • GT:  is greater than value.
  • GTE: is greater than or equal to value.
  • BETWEEN: is within the specified range between value and highValue.
  • IN: is included in the specified values array. This operator is case-sensitive, so inputted values must be in lowercase. 
  • NOT_IN: is not included in the specified values array.
  • HAS_PROPERTY: has a value for the specified property.
  • NOT_HAS_PROPERTY: does not have a value for the specified property.

Learn more about filtering CRM searches.

property
String

The property to filter by.

value
String or number

The property value to filter by.

values
String or number

The property values to filter by when using an operator that requires an array, such as IN.

highValue
String or number

The upper value to filter by when using an operator that requires a range, such as BETWEEN.

Association pivot

The CrmAssociationPivot component renders a list of associated records organized by their assigned association label. You'll specify the type of records that you want to appear along with table attributes such as pagination, sorting, and more. You can either return all labels or specify the labels to return.

ui-ext-components-associationspivot

objectTypeId  string  (required)

The numeric ID of the type of associated object to display (e.g., 0-1 for contacts). See full list of object IDs.

associationLabels  array

Filters results by specific association labels. By default, all association labels will appear.

maxAssociations  number

The number of items to return in each association label group before displaying a "Show more" button.

preFilters  array

Filters the data by specific values of the associated records. Review the filtering options above for more information.

sort  array

The default sorting behavior for the table. In each sort object in the array, you'll specify the following:

  • columnName: the column to sort by.
  • direction: the direction to sort by. Can be either 1 (ascending) or -1 (descending). By default, order is ascending.
const Extension = () => { return ( <CrmAssociationPivot objectTypeId="0-1" associationLabels={["CEO", "CEO of subsidiary", "Co-founder"]} maxAssociations={10} preFilters={[ { "operator": "NOT_IN", "property": "dealstage", "values": ["closedwon"] } ]} sort={[ { "columnName": "createdate", "direction": -1 } ]} /> ); };

Association property list

The CrmAssociationPropertyList component renders a list of properties belonging to a record associated with the currently displaying record. For example, you can use this component to display properties of a company record from its associated contact record. You can edit these property values inline and will automatically save when leaving the field or pressing Enter.

ui-extensions-component-associationpropertylist

 

properties  array (required)

The list of properties to display from the associated record, up to 12.

objectTypeId  string (required)

The numeric ID of the type of associated object to display (e.g., 0-1 for contacts). See full list of object IDs.

associationLabels  array

When provided, returns associated records that have all specified labels.

filters  array

Filters the data by specific values of the associated records. Review the filtering options above for more information.

sort  array

The default sorting behavior for the returned results. In each sort object in the array, you'll specify the following:

  • columnName: the column to sort by.
  • direction: the direction to sort by. Can be either 1 (ascending) or -1 (descending). By default, order is ascending.
const Extension = () => { return ( <CrmAssociationPropertyList objectTypeId="0-2" properties={[ 'name', 'domain', 'city', 'state' ]} filters={[ { operator: 'EQ', property: 'domain', value: 'meowmix.com' } ]} /> ); };

Association table

The CrmAssociationTable component renders a table of associated records with optional filtering, sorting, and search methods. You'll specify the type of records that you want to appear along with the properties to display as columns.

ui-ext-components-associationstable

 

objectTypeId  string (required)

The numeric ID of the type of associated object to display (e.g., 0-1 for contacts). See full list of object IDs.

propertyColumns  array (required)

The properties to add as table columns.

quickFilterProperties  array

The properties that appear as filters above the table. When included, the "Association label" quick filter will always display. See note below for more details on this prop.

associationLabelFilter  boolean

When set to false, hides the "Association label" quick filter above the table.

searchable  boolean

Set to false to hide the search box above the table.

pagination  boolean

Set to false to hide the pagination navigation below the table.

pageSize  number

The number of rows to include per page of results. Include the pagination property to enable users to navigate through returned results.

preFilters  array

Filters the data by specific values of the associated records. Review the filtering options above for more information.

sort  array

The default sorting behavior for the table. In each sort object in the array, you'll specify the following:

  • columnName: the column to sort by.
  • direction: the direction to sort by. Can be either 1 (ascending) or -1 (descending). By default, order is ascending.
const Extension = () => { return ( <CrmAssociationTable objectTypeId="0-3" propertyColumns={['dealname', 'amount', 'description']} quickFilterProperties={['createdate']} pageSize={10} preFilters={[ { operator: 'EQ', property: 'dealstage', value: 'contractsent', }, ]} sort={[ { direction: 1, columnName: 'amount', }, ]} searchable={true} pagination={true} /> ); };

Please note: for quickFilterProperties:

  • By default, four quick filters will display automatically depending on the object type.
    • Contacts (0-1): [ 'hubspot_owner_id', 'createdate', 'hs_lead_status', 'notes_last_updated' ]
    • Companies (0-2): [ 'hubspot_owner_id', 'hs_lead_status', 'notes_last_updated', 'createdate' ]
    • Deals (0-3): [ 'hubspot_owner_id', 'closedate', 'createdate', 'dealstage' ]
    • Tickets (0-5): [ 'hubspot_owner_id', 'createdate', 'hs_pipeline_stage', 'hs_lastactivitydate' ]
  • Custom objects do not have default quick filters
  • An empty array ([]) will remove any default quick filters except for "Association label".

Data highlight

The CrmDataHighlight component renders a list of properties along with their values. You can use this component to surface important property data from either the currently displaying record or another specified record.

data-highlight

 

properties  array (required)

The list of properties to display, up to four. By default, will show property data from the currently displaying record. Specify objectTypeId and objectId to pull data from another record.

objectTypeId  string

The numeric ID of the type of associated object to display (e.g., 0-1 for contacts). See full list of object IDs.

objectId  string

The ID of the CRM record to display property data from.

const Extension = () => { return ( <CrmDataHighlight properties={["createdate", "lifecyclestage", "hs_num_open_deals", "hs_num_child_companies"]} /> ); };

Property list

The CrmPropertyList component renders a list of properties along with their values. You can use this component to surface important property data from either the currently displaying record or another specified record. You can edit these property values inline and will automatically save when leaving the field or pressing Enter.

ui-ext-components-propertylist

 

properties  array (required)

The list of properties to display, up to 12. By default, will show property data from the currently displaying record. Specify objectTypeId and objectId to pull data from another record.

direction  string

The layout direction of the table. Can be one of: 

  • column (default): displays properties in single column.
  • row: displays properties in a grid from left to right.
objectTypeId  string

The numeric ID of the type of associated object to display (e.g., 0-1 for contacts). See full list of object IDs.

objectId  string

The ID of the CRM record to display property data from.

const Extension = () => { return ( <CrmPropertyList properties={[ 'lastname', 'email', 'createdate', 'address', 'city', 'state', 'zip', ]} direction="row" /> ); };

Report

The CrmReport component renders a single object report. The report data will automatically filter for the currently displaying record, as long as there is an association between the displaying record and records included in the report. For example, using this component you can display a single object report that shows which deals closed this quarter. When viewing the report on a contact record, the report will only display data from deals associated with that contact. If no deals are associated with the contact, the report will display unfiltered.

This component requires you to specify the ID of the report to render. To get a report's ID:

  • In your HubSpot account, navigate to Reports Reports.
  • Click the name of the report you want to display.
  • In the URL, copy the number that is not your HubID.
report-id-in-URL

ui-ext-components-report

Please note: users must have permissions to view reports to view the component.

 

reportId  string 

The ID of the single object report, which can be found in the URL when viewing the report.

const Extension = () => { return ( <CrmReport reportId="6339949" />; ); };

Stage tracker

The CrmStageTracker component renders a lifecycle or pipeline stage progress bar and a list of properties. Available for contacts, companies, deals, tickets, and custom objects.

Use this component to show stage progress for the currently displaying record, or you can specify a record. You can also edit the property values inline and your changes will automatically save when leaving the field or pressing Enter.

ui-extensions-component-dealstagetracker

 

objectId  string

The ID of the record to display. If not specified, will default to displaying information for the currently displaying record.

objectTypeId  string

The ID of the type of record to display (e.g., 0-3 for deals, 0-5 for tickets). See full list of object IDs. If not specified, will default to displaying information for the currently displaying record.

properties  array (required)

The names of the properties to display. You can specify up to four properties, but properties beyond that will be ignored. If omitted, a set of default properties will render, depending on the object type.

shouldShowProperties  boolean 

Whether the show the list of properties below the stage progress indicator. When set to false, will not show the list of properties, even if provided.

const Extension = () => { return ( <CrmStageTracker objectId="13833764681" objectTypeId="0-3" properties={[ 'dealname', 'amount', ]} /> ); };

CRM statistics

The CrmStatistics component renders data summaries calculated from the currently displaying CRM record's associations. For example, you can use this component to display data such as:

  • The average revenue of all of a contact’s associated companies.
  • The total number of times that a company has been contacted based on all of their associated tickets.
  • The maximum number of days to close from all of a company's associated deals.

To render data, you'll specify the properties you want to read from the associated records along with the type of calculation to perform on the property values. For each property, you can also include filters to narrow down the records that are included in the calculation.

ui-extension-component-crm-statistics

objectTypeId  string (required)

The ID of the type of record to fetch data from (e.g., 0-3 for deals, 0-5 for tickets). See full list of object IDs.

statistics  array (required)

An array containing objects for each set of data to fetch. Each item in the array will contain:

  • label: the label to display above the statistic.
  • statisticType: the type of statistic to request:
    • SUM: the sum of the values of the specified property.
    • AVG: the average of the values of the specified property.
    • MIN: the smallest value of the specified property.
    • MAX: the largest value of the specified property.
    • COUNT: the number of associated records with a value for the specified property.
    • DISTINCT_APPROX: an approximate count of distinct values for the specified property.
    • PERCENTILES: the property value at which a certain percentage of observed values occur. When using this type, you'll also need to include a percentile field to specify the percentile to display. percentile takes an integer from 0-100.
  • propertyName: the name of the property to fetch data from. The property type must be number, date, or datetime. Specifying any other type of property will result in the statistic showing -- for its value.
  • filterGroups: an optional array containing filters that specify which associated records to fetch property data from. You can include up to three filter group objects with each filter containing up to three filters. Exceeding these limits will result in the statistic showing -- for its value. Filters are structured the same way as filters in the CRM search API.
const Extension = () => { return ( <CrmStatistics objectTypeId="0-3" statistics={[ { label: 'Average Deal Amount', statisticType: 'AVG', propertyName: 'amount', }, { label: '50th Percentile Deal Amount', statisticType: 'PERCENTILES', propertyName: 'amount', percentile: 50, }, { label: 'Time Left for Most Important Upcoming Deal', statisticType: 'MIN', propertyName: 'days_to_close', // The filters below narrow the fetched // deals by the following criteria: // - Amount must be >= 10,000 // - Deal must not be closed filterGroups: [ { filters: [ { operator: 'GTE', property: 'amount', value: 10000, }, { operator: 'EQ', property: 'hs_is_closed', value: "false", }, ], }, ], }, ]} /> ); };

CRM action components

CRM action components provide a built-in set of CRM-related actions, including adding notes to records, opening a one-to-one email composition window, creating new records, and more. Each component can perform the same set of actions, so which component to choose will depend on your needs and preferences. Check out the component design guidelines for additional guidance. 

CRM action components are imported from @hubspot/ui-extensions/crm.

import { CrmActionButton, CrmActionLink } from '@hubspot/ui-extensions/crm';

crm-card-actions

  1. CRM action buttons: buttons for previewing a CRM record or creating a new associated record.
  2. CRM action link:  a link for creating a new note on the deal record on click.
  3. CRM card actions: buttons in the top right of the card that contain lists of actions in dropdown menus.

Users can only take actions through these components when they have the proper permissions. For example, if a user doesn't have permission to create deal records, they won't be able to use a CRM action component to create a deal record. Instead, an error message will be generated and returned through an optional onError callback.

Each action requires an actionType and actionContext.

  • actionType: the type of action. See the available actions section below.
  • actionContext: the CRM object and record context required for the action to be performed. For example, to include an action to open a preview sidebar for a specified record, you'll need to provide the record's objectTypeId and objectId in actionContext. See the available actions for more information about what's required for each action.

Action button

The CrmActionButton component renders a button that can execute a built-in set of CRM actions. See list of available actions for more information. This component can be used in extensions that are in either the sidebar or middle column.

ui-extensions-crm-action-button

 

actionType  string (required)

The type of action for the button to perform. See list of available actions below.

actionContext  object (required)

An object containing the CRM object and record context for performing the action. See list of available actions below for required context values.

variant  string

Sets the color variation of the button. Values include:

  • primary
  • secondary (default)
  • destructive
disabled  boolean

Set to true to render the button in a disabled, greyed-out state.

type  array

Sets the HTML attribute role of the button. Can be one of:

  • button (default)
  • reset
  • submit
onError  function

An optional callback that will be passed any error messages that were generated. Common errors include missing required context values or the user having insufficient permissions to perform an action.

const dealContext = { objectTypeId: "0-3", objectId: 14795354663, }; const associateContext = { objectTypeId: "0-3", association: { objectTypeId: "0-1", objectId: 769851, }, }; hubspot.extend(({ context, runServerlessFunction, actions }) => { return ( <> <CrmActionButton actionType="PREVIEW_OBJECT" actionContext={dealContext} variant="secondary" > Preview existing Deal </CrmActionButton> <CrmActionButton actionType="OPEN_RECORD_ASSOCIATION_FORM" actionContext={associateContext} variant="primary" > Create new Deal </CrmActionButton> </> ); });

The CrmActionButton component renders a clickable link that can execute a built-in set of CRM actions. See list of available actions for more information. This component can be used in extensions that are in either the sidebar or middle column.

ui-extensions-crm-action-link

 

actionType  string (required)

The type of action for the button to perform. See list of available actions below.

actionContext  object (required)

An object containing the CRM object and record context for performing the action. See list of available actions below for required context values.

variant  string

Sets the color variation of the button. Values include:

  • primary (default)
  • light 
  • dark
  • destructive
onError  function

An optional callback that will be passed any error messages that were generated. Common errors include missing required context values or the user having insufficient permissions to perform an action.

const dealContext = { objectTypeId: "0-3", objectId: 14795354663, }; hubspot.extend(({ context, runServerlessFunction, actions }) => { return ( <> <CrmActionLink actionType="ADD_NOTE" actionContext={dealContext} > Add a note about this deal to the record </CrmActionLink> </> ); });

Action menu

The CrmCardActions component renders a smaller standalone or dropdown menu button that can contain multiple CRM actions. See list of available actions for more information. This component can only be used in extensions that are in the middle column.

2023-08-29_15-08-37 (1)

 

type  string (required)

The type of button to render:

  • action-library-button: a standalone button that can perform one action. 
  • dropdown: a dropdown menu button containing multiple action options. When using this type, you'll need to include an options array containing each action.
options  array

Array containing an object for each available action. See list of available actions below.

actionContext  object (required)

An object containing the CRM object and record context for performing the action. See list of available actions below for required context values.

disabled  boolean

Set to true to render the button in a disabled, greyed-out state.

tooltipText  string

Text that displays above the button on hover.

<CrmCardActions actionConfigs={[ { type: "action-library-button", label: "Preview", actionType: "PREVIEW_OBJECT", actionContext: { objectTypeId:"0-3", objectId: 14795354663 }, tooltipText: "Preview this deal record." }, { type: "dropdown", label: "Activities", options: [ { type: "action-library-button", label: "Send email", actionType: "SEND_EMAIL", actionContext: { objectTypeId: "0-1", objectId: 769851 } }, { type: "action-library-button", label: "Add note", actionType: "ADD_NOTE", actionContext: { objectTypeId: "0-1", objectId: 769851 }, } ] } ]} />

Preview a CRM record

The PREVIEW_OBJECT action opens a preview sidebar for the specified CRM record.

Requires the following actionContext:

  • objectTypeId: the CRM record's object type (e.g., 0-1 for contacts). See full list of object IDs.
  • objectId: the ID of the CRM record to preview.
<CrmActionButton actionType="PREVIEW_OBJECT" actionContext={{ objectTypeId: "0-3", objectId: 123456 }} variant="secondary" > Preview deal </CrmActionButton>

Create a note

The ADD_NOTE action opens a note composition window, enabling users to add a note to the specified CRM record.

Requires the following actionContext:

  • objectTypeId: the CRM record's object type (e.g., 0-1 for contacts). See full list of object IDs.
  • objectId: the ID of the CRM record.
<CrmActionButton actionType="ADD_NOTE" actionContext={{ objectTypeId: "0-3", objectId: 123456 }} variant="secondary" > Create note </CrmActionButton>

Send a one-to-one email

The SEND_EMAIL action opens a one-to-one email composition window, enabling users to send an email to the specified contact or the contacts associated with the specified record.

Requires the following actionContext:

  • objectTypeId: the CRM record's object type (e.g., 0-1 for contacts). See full list of object IDs.
  • objectId: the ID of the CRM record to send the email to.
<CrmActionButton actionType="SEND_EMAIL" actionContext={{ objectTypeId: "0-3", objectId: 123456 }} variant="secondary" > Send email </CrmActionButton>

Schedule a meeting

The SCHEDULE_MEETING action opens a window for scheduling a meeting.

Requires the following actionContext:

  • objectTypeId: the CRM record's object type (e.g., 0-1 for contacts). See full list of object IDs.
  • objectId: the ID of the CRM record to schedule the meeting with.
<CrmActionButton actionType="SCHEDULE_MEETING" actionContext={{ objectTypeId: '0-1', objectId: 123456 }} > Schedule meeting </CrmActionButton>

Create an associated record

The OPEN_RECORD_ASSOCIATION_FORM action opens a side panel for creating a new record to be associated with another.

Requires the following actionContext:

  • objectTypeId: the type of CRM record to create (e.g., 0-2 for companies). See full list of object IDs.
  • association: an object containing information about the record that the new one will be associated with. This is typically the currently displaying record. Contains:
    • objectTypeId: the type of CRM record to associate the new one with.
    • objectId: the ID of the CRM record to associate the new one with.
<CrmActionButton actionType="OPEN_RECORD_ASSOCIATION_FORM" actionContext={{ objectTypeId: '0-2', association: { objectTypeId: '0-1', objectId: 123456 } }} > Create new record </CrmActionButton>

The ENGAGEMENT_APP_LINK action navigates the user to a specific engagement on a CRM record timeline, such as a call or task.

Requires the following actionContext:

  • objectTypeId: the type of CRM record to navigate to (e.g., 0-2 for companies). See full list of object IDs.
  • objectId: the ID of the CRM record to navigate to.
  • engagementId: the ID of the engagement, such as a task or note.
  • external: optionally, set to true to navigate to the engagement in a new browser tab.
<CrmActionButton actionType="ENGAGEMENT_APP_LINK" actionContext={{ objectTypeId: "0-2", objectId: 2763710643, engagementId: 39361694368 }} variant="secondary" > Open note </CrmActionButton>

The RECORD_APP_LINK action navigates the user to a specific CRM record.

Requires the following actionContext:

  • objectTypeId: the type of CRM record to navigate to (e.g.,  0-2 for companies). See full list of object IDs.
  • objectId: the ID of the CRM record to navigate to.
  • external: optionally, set to true to navigate to the record in a new browser tab.
  • includeEschref: optionally, set to true to include a Back button in the top left corner of the opened CRM record to navigate the user back to the original record.
    ui-extensions-crm-action-back-button
<CrmActionButton actionType="RECORD_APP_LINK" actionContext={{ objectTypeId: "0-2", objectId: 2763710643, includeEschref: true }} variant="secondary" > View company </CrmActionButton>

The PAGE_APP_LINK navigates the user to any page within the HubSpot account. Use this action when a user would need to navigate to a non-CRM record account page, such as the email tool.

Requires the following actionContext:

  • path: the URL path of the HubSpot page. This path is relative to https://app.hubspot.com and should begin with /.
  • external: optionally, set to true to navigate to the page in a new browser tab.
<CrmActionButton actionType="PAGE_APP_LINK" actionContext={{ path: "/email/123456/analyze?emailType=followup-2", external: true }} variant="secondary" > Open email dashboard </CrmActionButton>

The EXTERNAL_URL action navigates the user to a website page in a new tab.

Requires the following actionContext:

  • href: the URL, which must begin with http or https. When protocol is not specified, HubSpot will automatically prefix the URL with https.
<CrmActionButton actionType="EXTERNAL_URL" actionContext={{ href: "https://www.google.com", }} variant="secondary" > Open Google </CrmActionButton>

Was this article helpful?
This form is used for documentation feedback only. Learn how to get help with HubSpot.