In this tutorial, you'll use React to create a Zendesk Support app. To build the app, you'll use the React app scaffold and Zendesk Garden React components. You can use the app's code as a starting point for your own app.

The app displays a timeline of events for a ticket requester. Agents can access the app while viewing a ticket in the Agent Workspace.

Disclaimer: Zendesk provides this article for instructional purposes only. Zendesk doesn't provide support for the app or example code in this tutorial. Zendesk doesn't support third-party technologies, such as React, Babel, or Webpack.

What you'll need

To complete this tutorial, you'll need the following:

Creating the app files

First, use the React app scaffold to create starter files for an app named User events.

  1. This tutorial requires Node.js 16.17.0. If needed, use nvm to install and use this Node.js version:

    nvm install 16.17.0nvm use 16.17.0
  2. In your shell, navigate to the folder where you want to store the app. Example:

    cd projects
  3. In the folder, run:

    zcli apps:new --scaffold=react
  4. At the prompts, enter the following values:

    • Directory name: user_events
    • Author's name: Your name
    • Author's email: Your email address
    • App name: User events

    ZCLI creates the files for your project in the user_events folder. To learn more about the React app scaffold's file structure, see the documentation on GitHub.

Updating and installing dependencies

The app uses Babel to compile JSX and other modern JavaScript into browser-ready code. The React app scaffold already includes Babel as a dependency. However, it uses an older version of Babel that's incompatible with some Zendesk Garden components.

Update the project's Babel dependencies and configs to the latest version. Then install the React and ReactDOM packages.

  1. In your shell, navigate to the project's root folder. Example:

    cd projects/user_events
  2. In the project's root folder, run:

    npx babel-upgrade --write

    The command updates the project's Babel dependencies and config files.

  3. Next, run:

    npm install --save-dev @babel/preset-react

    The command may take a while to run. It installs Babel presets for React. The presets include Babel plugins for converting JSX into browser-ready JavaScript. The command also installs any packages listed as dependencies in the project's package.json file.

  4. In the project's root folder, open .babelrc in your text editor. Replace the file's contents with the following:

    {  "presets": ["@babel/preset-env", "@babel/preset-react"]}

    This configures Babel to use the React presets you installed in step 3.

  5. In the project's root folder, open webpack.config.js. In the module.exports object, remove 'babel-polyfill' from the entry.app array.

    ...module.exports = {  entry: {    app: [      './src/javascripts/locations/ticket_sidebar.js',      './src/index.css'    ]  },  ...}

    The babel-polyfill package is deprecated. You removed the package from your project when you updated Babel in step 2.

  6. Save .babelrc and webpack.config.js.

  7. In the project's root folder, run:

    The command installs the React and ReactDOM packages. This tutorial uses React 17.

Reviewing the project's source files

The app scaffold uses Webpack to build Zendesk app files from source files in the src folder. When run, Webpack places the final app files in a dist folder in the project's root.

As part of the build, Webpack bundles any required JavaScript for the app into a single file. You can configure starting points for the bundle in the entry.app array of webpack.config.js. Your project uses src/javascripts/locations/ticket_sidebar.js as a starting point:

...module.exports = {  entry: {    app: [      './src/javascripts/locations/ticket_sidebar.js',      ...    ]  },  ...}

The final bundled file includes any modules imported into ticket_sidebar.js using JavaScript's import or require keywords. Your project's ticket_sidebar.js file includes an import of the App module from src/javascripts/modules/app.js:

import App from '../modules/app'
/* global ZAFClient */var client = ZAFClient.init()
client.on('app.registered', function (appData) {  return new App(client, appData)})

When the app loads, the code in ticket_sidebar.js creates a new instance of App. It passes the ZAF client and context data to the App instance. This lets you use the ZAF client in the App module's code. You can edit the App module in app.js to make changes to the Zendesk app.

Adding React components

Next, update the App module in app.js to render a React component. As a test, use the Button component from Zendesk Garden.

To ensure the Button component renders correctly, wrap the app in a Theme provider. Zendesk Garden components require a Theme provider wrapper for styling.

  1. In the project's root folder, run:

    npm install @zendeskgarden/react-theming @zendeskgarden/react-buttons

    The command installs packages for the Theme provider and Button components.

  2. In the project's src/javascripts/modules folder, open app.js. Replace the file's contents with the following:

    import React from 'react'import { render } from 'react-dom'import { ThemeProvider, DEFAULT_THEME } from '@zendeskgarden/react-theming'import { Button } from '@zendeskgarden/react-buttons'
    export default function App () {  const container = document.querySelector('.main')  render(    <ThemeProvider theme={{ ...DEFAULT_THEME }}>      <Button>Click me</Button>    </ThemeProvider>,    container  )}

    The code imports modules from the React, ReactDOM, and Zendesk Garden packages you installed earlier. It also exports the App module as a function. The function uses ReactDOM's render() method to render the Theme Provider and Button components. The method renders the components in the <div> with the "main" CSS class in iframe.html.

  3. Save app.js.

Running the app locally

Run your app locally to ensure it displays the Button component.

  1. In the project's root folder, run:

    npm run watch

    The command uses Webpack to build and output the Zendesk app files to the dist folder. After the initial build, the command watches for changes to files in the src folder. If it detects a change, it automatically rebuilds the output files in dist.

    Note: To stop the command, press Ctrl+C.

  2. In another terminal session, run the following command in the project's root folder:

    npm run start

    The command starts a local ZCLI web server.

    Note: To stop the command, press Ctrl+C.

  3. In your browser's private or incognito window, sign in to Zendesk Support and go to the Agent Workspace. From the workspace, open a new or existing ticket.

    The URL should look like this:

    https://{subdomain}.zendesk.com/agent/tickets/{ticket_id}

  4. Append ?zcli_apps=true to the URL and press Enter. The URL should now look like this:

    https://{subdomain}.zendesk.com/agent/tickets/{ticket_id}?zcli_apps=true

  5. Click the Apps icon.

    The app displays the Button component.

Adding the timeline component

Next, update the App module to fetch the ticket requester's events. Use Zendesk Garden's Timeline component to display the events in the app.

  1. In another terminal session, run the following command in the project's root folder:

    npm install styled-components @zendeskgarden/react-accordions @zendeskgarden/react-typography

    The command installs the packages required for the Timeline component.

  2. In the src/javascripts/modules folder, open app.js. Replace the file's contents with the following:

    import React from 'react'import { render } from 'react-dom'import { resizeContainer } from '../lib/helpers'import EventTimeline from './event_timeline'
    const MAX_HEIGHT = 1000
    class App {  constructor (client, appData) {    this._client = client    this._appData = appData    this.initializePromise = this.init()  }
      async init () {    const requesterId = (await this._client.get('ticket.requester.id'))['ticket.requester.id']    const eventRequestOptions = {      url: `/api/v2/users/${requesterId}/events`,      data: `page[size]=5`    }
        const events = (await this._client.request(eventRequestOptions))    // Sorts events by created_at timestamp    const sortedEvents = events.events.sort((a, b) => (a.created_at > b.created_at) ? 1 : -1)    const container = document.querySelector('.main')
        render(<EventTimeline events={sortedEvents} />, container)    return resizeContainer(this._client, MAX_HEIGHT)  }}
    export default App

    The code exports the App module as a class. When initialized, the class uses the ZAF client's get() method to fetch the ticket requester's user id. It then uses the id to make a request() call to the Get Zendesk User Events endpoint. The endpoint returns up to five events for the requester.

    To render the events, the class uses an EventTimeline component from a local event_timeline.js file. You'll create this component and file in the next step.

  3. In the src/javascripts/modules folder, create an event_timeline.js file. Paste the following into the file:

    import React from 'react'import styled from 'styled-components'import { ThemeProvider, DEFAULT_THEME } from '@zendeskgarden/react-theming'import { Timeline } from '@zendeskgarden/react-accordions'import { Span } from '@zendeskgarden/react-typography'import { toSentenceCase, formatDate } from '../lib/helpers'
    const StyledSpan = styled(Span).attrs({ isBold: true })`  display: block;  `
    export default function EventTimeline ({events}) {  return (    <ThemeProvider theme={{ ...DEFAULT_THEME }}>      <Timeline>        {events.map((event) => {          return (            <Timeline.Item key={event.id} data-event-id={event.id}>              <Timeline.Content>                <StyledSpan data-type='type'>{toSentenceCase(event.type)}</StyledSpan>                <Span hue='grey' data-type='date'>{formatDate(event.created_at)}</Span>              </Timeline.Content>            </Timeline.Item>          )        })}      </Timeline>    </ThemeProvider>  )}

    The file exports the EventTimeline component as a function. The function loops through the events returned by the Get Zendesk User Events request. It renders each event's type and created_at values using Zendesk Garden's Timeline component.

    The file also imports the toSentenceCase and formatDate functions to format event values. You'll create these functions in the next step.

  4. In the src/javascripts/lib folder, open helpers.js. Add the following toSentenceCase and formatDate functions to the bottom of the file:

    .../*** Helper to convert snake case strings to sentence case* @param {String} string Snake case string* @return {String} Sentence case string*/export function toSentenceCase (string) {  const finalString = string.replace(/_/g, ' ')  return finalString.charAt(0).toUpperCase() + finalString.slice(1)}
    /*** Helper to format ISO 8601 timestamps as human-readable datetime* @param {String} date ISO 8601 timestamp* @return {String} Formatted date. Example: Sep 1, 2099 2:55 PM*/export function formatDate (date) {  const formattedDate = new Date(date)  const options = {    year: 'numeric',    month: 'short',    day: 'numeric',    hour: 'numeric',    minute: 'numeric'  }  return formattedDate.toLocaleDateString('en-us', options)}
  5. In your browser, reload the Agent Workspace page. The app now displays the event timeline.

Installing the app

As an optional step, you can upload and install the app as a private app in your Zendesk Support instance.

  1. If running, stop the npm run start and npm run start commands by pressing Ctrl+C in the respective terminal sessions.

  2. In the project's root folder, run:

    npm run build

    The command builds outputs the app files to the dist folder.

  3. In the project's root folder, run:

    zcli apps:create ./dist

    ZCLI packages, uploads, and installs the app to your Zendesk instance.

  4. In Admin Center, click the Apps and integrations icon () in the sidebar. Then select Apps > Zendesk Support apps.

    The app appears in the list of installed apps on the My Apps page.

Congratulations! You've created a Zendesk app that uses React. As a next step, you can get your app ready for production. Consider tackling the following tasks:

  • Adding error handling for the ZAF client's request() call

  • Limiting the Get Zendesk User Events request to specific event sources or times

  • Localizing the app's strings using the React app scaffold's i18n module

  • Updating the unit tests in the spec folder