Developer Docs

Custom Components

Getting Started

Modalities

Touchpoint relies on modalities defined within the NLX application to send structured data from the NLX conversation flow to touchpoint. For each Modality defined in your conversational application that you wish to use with Touchpoint, you must create a component and explicitly enable that modality when creating your touchpoint instance.

Defining your Component

Each component should accept an object with

data and conversationHandler to access the conversation context sent from the NLX Application.

  • data: Can be any type. It will match the schema set in the modality within NLX.
  • conversationHandler: The ConversationHandler. Functions to access the conversational context and send data back to NLX.

Add the Component to the

customModalities configuration option paired with the name of Modality in NLX. In the example below the modality is named "MyComponentModality".

Basic Component Structure

Every custom component follows the same pattern. Here's a simple example in both JavaScript and HTML formats:

1<html lang="en"> 2 <head> 3 <title>Touchpoint Sample HTML</title> 4 <meta name="viewport" content="width=device-width, initial-scale=1"> 5 </head> 6 <body> 7 <script type="module"> 8 import { create, React, html } from "https://unpkg.com/@nlxai/touchpoint-ui@1.1.3/lib/index.js?module"; 9 10 const SimpleComponent = ({ data, conversationHandler }) => { 11 return html`<BaseText>${data.message}</BaseText>`; 12 }; 13 14 const touchpoint = await create({ 15 config: { 16 applicationUrl: "YOUR_APPLICATION_URL", 17 headers: { "nlx-api-key": "YOUR_API_KEY" }, 18 languageCode: "en-US", 19 }, 20 customModalities: { 21 SimpleModality: SimpleComponent, 22 }, 23 }); 24 25 </script> 26 </body> 27</html>

HTML Template Syntax

The

html template literal tag allows you to create components without requiring JSX transpilation or build systems. This approach is powered by the htm library.

How the html Template Tag Works

The

html tag is a template literal function that:

  • Parses HTML-like syntax at runtime
  • Automatically imports all Touchpoint UI components

Accessing Components in HTML

When using HTML, always destructure the components you need from

nlxai.touchpointUi:

HTML

1const { html, React, Icons } = nlxai.touchpointUi;

This gives you access to:

  • html - The template tag for creating components
  • React - React utilities like useState
  • Icons - All available icon components
  • All other Touchpoint components (BaseText, CustomCard, etc.)

HTML vs JSX Quick Reference

FeatureJSXHTML Template
Importimport { html } from "@nlxai/touchpoint-ui"const { html } = nlxai.touchpointUi
Component<BaseText>Hello</BaseText>html\Hello``
Propslabel="Click me"label="Click me"
Dynamic PropsonClick={() => console.log()}onClick=${() => console.log()}

Key Differences from JSX

  • No build step required
  • Use ${} for interpolation instead of {}
  • Nested components require nested html templates
  • All Touchpoint components are automatically available
  • Ideal for adding components to existing JavaScript codebases

Example Component in JSX and HTML

JavaScript

1import { React, BaseText, TextButton, Icons } from "@nlxai/touchpoint-ui"; 2 3const MyComponent = ({ data }) => ( 4 <> 5 <BaseText>{data.title}</BaseText> 6 <TextButton 7 label="Click me" 8 Icon={Icons.ArrowForward} 9 onClick={() => console.log("Clicked!")} 10 /> 11 </> 12);

HTML

1<script> 2 const MyComponent = ({ data }) => { 3 const { html, Icons } = nlxai.touchpointUi; 4 5 return html` 6 <BaseText>${data.title}</BaseText> 7 <TextButton 8 label="Click me" 9 Icon=${Icons.ArrowForward} 10 onClick=${() => console.log("Clicked!")} 11 /> 12 `; 13 }; 14</script>

Managing State, Events, User Selection within Components

Components often need to track state (like which item is selected) and handle user interactions (like clicks). Touchpoint provides React's state management and event handling patterns.

useState in Touchpoint Components

useState returns an array with two elements:

  1. The current state value
  2. A function to update the state

When you call the update function, React will re-render the component with the new state value.

1<html lang="en"> 2 <head> 3 <title>Touchpoint Sample HTML</title> 4 <meta name="viewport" content="width=device-width, initial-scale=1"> 5 </head> 6 <body> 7 <script type="module"> 8 import { create, React, html } from "https://unpkg.com/@nlxai/touchpoint-ui@1.1.3/lib/index.js?module"; 9 10 const SelectableCard = ({ data, conversationHandler }) => { 11 // Declare state variable with initial value of false 12 const [isSelected, setIsSelected] = React.useState(false); 13 14 return html` 15 <CustomCard 16 selected=${isSelected} 17 onClick=${() => { 18 // Update the state when clicked 19 setIsSelected(true); 20 // Send the selection to NLX 21 conversationHandler.sendChoice(data.id); 22 }} 23 > 24 <CustomCardRow 25 left=${html`<BaseText faded>Status</BaseText>`} 26 right=${html`<BaseText 27 >${isSelected ? "Selected" : "Not Selected"}</BaseText 28 >`} 29 /> 30 </CustomCard> 31 `; 32 }; 33 34 </script> 35 </body> 36</html>

Event Handler Pattern

Always use arrow functions for event handlers in both JavaScript and HTML:

1// Correct - arrow function 2onClick=${() => conversationHandler.sendChoice(data.id)} 3 4// Incorrect - immediate execution 5onClick=${conversationHandler.sendChoice(data.id)}

This ensures the function is called when the user clicks, not when the component renders.

Here's a complete carousel implementation following the standard pattern with CustomCardImageRow at the top and faded labels:

1<html lang="en"> 2 <head> 3 <title>Touchpoint Sample HTML</title> 4 <meta name="viewport" content="width=device-width, initial-scale=1"> 5 </head> 6 <body> 7 <script type="module"> 8 import { create, React, html } from "https://unpkg.com/@nlxai/touchpoint-ui@1.1.3/lib/index.js?module"; 9 10 const ItemsCarousel = ({ data, conversationHandler }) => { 11 // Track which item is selected 12 const [selectedItemId, setSelectedItemId] = React.useState(null); 13 14 return html` 15 <Carousel> 16 ${data.map( 17 (item) => html` 18 <CustomCard 19 key=${item.id} 20 selected=${item.id === selectedItemId} 21 onClick=${() => { 22 // Update selected state 23 setSelectedItemId(item.id); 24 // Send choice to NLX 25 conversationHandler.sendChoice(item.id); 26 }} 27 > 28 <!-- Image at the top --> 29 <CustomCardImageRow src=${item.thumbnail} alt=${item.name} /> 30 31 <!-- Faded label on left, normal text on right --> 32 <CustomCardRow 33 left=${html`<BaseText faded>Name</BaseText>`} 34 right=${html`<BaseText>${item.name}</BaseText>`} 35 /> 36 37 <CustomCardRow 38 left=${html`<BaseText faded>Price</BaseText>`} 39 right=${html`<BaseText>${item.price}</BaseText>`} 40 /> 41 42 <CustomCardRow 43 left=${html`<BaseText faded>Status</BaseText>`} 44 right=${html`<BaseText>${item.status}</BaseText>`} 45 /> 46 </CustomCard> 47 `, 48 )} 49 </Carousel> 50 `; 51 }; 52 53 // Register the component 54 const touchpoint = await create({ 55 config: { 56 applicationUrl: "YOUR_APPLICATION_URL", 57 headers: { "nlx-api-key": "YOUR_API_KEY" }, 58 languageCode: "en-US", 59 }, 60 customModalities: { 61 ItemsCarouselModality: ItemsCarousel, 62 }, 63 }); 64 65 </script> 66 </body> 67</html>

Troubleshooting Common Issues

HTML-Specific Issues

"nlxai is not defined"

  • Cause: Script running before Touchpoint UI loads
  • Solution: Ensure the script tag has defer attribute and wrap code in contentLoaded():
1<script 2 defer 3 src="https://unpkg.com/@nlxai/touchpoint-ui/lib/index.umd.js" 4></script> 5<script> 6 contentLoaded().then(() => { 7 // Your code here 8 }); 9</script>

Components not rendering

  • Cause: Using JSX syntax instead of template syntax
  • Solution: Use ${html...} for nested components:
1// Wrong 2left={<Carousel>...</Carousel>} 3 4// Correct 5left=${html`<Carousel>...</Carousel>`}

"React.useState is not a function"

  • Cause: React not properly imported
  • Solution: Destructure React from nlxai.touchpointUi:
1const { React } = nlxai.touchpointUi;

General Issues

Component receives undefined data

  • Cause: Modality schema doesn't match expected data structure
  • Solution: Log the data to check structure. See Subscribing to events for methods to check data outside components.
1<html lang="en"> 2 <head> 3 <title>Touchpoint Sample HTML</title> 4 <meta name="viewport" content="width=device-width, initial-scale=1"> 5 </head> 6 <body> 7 <script type="module"> 8 import { create, React, html } from "https://unpkg.com/@nlxai/touchpoint-ui@1.1.3/lib/index.js?module"; 9 10 const MyComponent = ({ data }) => { 11 console.log("Received data:", data); 12 // Component code 13 }; 14 15 </script> 16 </body> 17</html>

Choice not sent to NLX

  • Cause: Missing or incorrect conversationHandler call
  • Solution: Ensure you're calling the correct method. See Sending Messages and Data for more information.
1// For choices 2conversationHandler.sendChoice(choiceId); 3 4// For slots 5conversationHandler.sendSlots({ slotName: value });

React Version Mismatch Error

  • Cause: Importing React from the parent project instead of from the touchpoint-ui package
  • Solution: Import React directly from the "@nlx/touchpoint-ui" package when using JSX to build custom components. This ensures that the components will be running in the same React context as the Touchpoint UI using the correct version of React.
1// React is available as React in touchpointui 2const [state, setState] = React.useState(initialValue);