Skip to main content

Hints

Hints item component

Source@dopt/react-hintsFigma

Overview

The hints component is powered by a hints block and is great way to call attetnion to UI elements to help users discover new features, provide contextual help, or nudge them towards a good next step.

A hints block is comprised of items, which are the unordered set of hints.

The hints component exposes two hooks and a family of UI components to easily build product hints or hotspots.

Installation

info

If you are using a particular React framework like Next.js, please check out our framework specific docs.

npm install @dopt/react-hints

Usage

The default export from @dopt/react-hints is a collection of components that you can use to structure and compose a hints item.

import Hint, { useHintsItem } from '@dopt/react-hints';

function MyHintsStep({ children }) {
const hintItem = useHintsItem('hints.project-creation');

if (!hintItem) {
return children;
}

return (
<Hint.Root active={hintItem.active}>
<Hint.Anchor>
<button style={{ position: 'relative' }}>
Create a project
<Hint.Indicator
onClick={() => hintItem.setOpen(!hintItem.open)}
style={{
bottom: -8,
right: -8,
}}
/>
</button>
</Hint.Anchor>
<Hint.Popover position="bottom" open={hintItem.open}>
<Hint.Content>
<Hint.Header>
<Hint.Title>{hintItem.title}</Hint.Title>
<Hint.CloseIcon onClick={() => hintItem.setOpen(false)} />
</Hint.Header>
<Hint.Body>{hintItem.body}</Hint.Body>
<Hint.Footer>
<Hint.CompleteButton onClick={hintItem.complete}>
{hintItem.completeLabel}
</Hint.CompleteButton>
<Hint.DismissAllButton>
{hintItem.dismissAllLabel}
</Hint.DismissAllButton>
</Hint.Footer>
</Hint.Content>
</Hint.Popover>
</Hint.Root>
);
}

Check out our hints example and our headless hints example for more in-depth usage.

Props

Root

The root element of the hints item.

NameTypeDescription
active?booleanDetermines the visibility of the component (default: false)
children?ReactNodeThe contents of the component
theme?ThemeA theme definition to attach to the component

Anchor

The element to anchor the hints item to.

NameTypeDescription
childrenReactElementA React element to anchor to

Indicator

The indicator element, typically contained within the anchor. Extends HTMLSpanElement.

NameTypeDescription
onClick?() => voidA handler for click that can be used to show the hint popover. Note that any event handler can be used here.
animate?booleanControl over whether the indicator is animated. Defaults to true.
style?React.CSSPropertiesStyle object for custom positioning of the indicator

Popover

The hints item popover. Extends HTMLDivElement.

NameTypeDescription
alignment?AlignmentDetermines how the component should align relative to the anchor element (default: center)
children?ReactNodeThe contents of the component
open?booleanA boolean determining whether the hint popover is open
offset?numberThe distance in px to position the component relative to the anchor element (default: 10)
position?SideThe side that the component should position relative to the anchor element (default: top)
theme?ThemeA theme definition to attach to the component

Content

The content of the hints item popover. Extends HTMLDivElement.

NameTypeDescription
children?ReactNodeThe contents of the component
theme?ThemeA theme definition to attach to the component

The header of the hints item popover. Extends HTMLElement.

NameTypeDescription
children?ReactNodeThe contents of the component
theme?ThemeA theme definition to attach to the component

Title

The title of the hints item popover. Extends HTMLHeadingElement.

NameTypeDescription
children?ReactNodeThe contents of the component
theme?ThemeA theme definition to attach to the component

Content

The content of the hints item popover. Extends HTMLDivElement.

NameTypeDescription
children?ReactNodeThe contents of the component
theme?ThemeA theme definition to attach to the component

DismissIcon

The dismiss icon of the hints item popover. Extends HTMLButtonElement.

NameTypeDescription
theme?ThemeA theme definition to attach to the component

Body

The body of the hints item popover. Extends HTMLDivElement.

NameTypeDescription
children?RichTextThe rich text contents of the component
theme?ThemeA theme definition to attach to the component

The footer of the hints item popover. Extends HTMLElement.

NameTypeDescription
children?ReactNodeThe contents of the component
theme?ThemeA theme definition to attach to the component

CompleteButton

The back button of the hints item popover. Extends HTMLButtonElement.

NameTypeDescription
children?ReactNodeThe contents of the component
theme?ThemeA theme definition to attach to the component

DismissAllButton

The next button of the hints item popover. Extends HTMLButtonElement.

NameTypeDescription
children?ReactNodeThe contents of the component
theme?ThemeA theme definition to attach to the component

Styling API

Learn more about styling and theming →

NameSelectorDescription
popover.dopt-hints-itemPopover element
indicator.dopt-hints-item__indicatorHint indicator
content.dopt-hints-item__contentContent container
header.dopt-hints-item__headerHeader containing title and dismiss icon
title.dopt-hints-item__titleTitle heading
dismissIcon.dopt-hints-item__dismiss-iconDisiss icon button
body.dopt-hints-item__bodyBody content
footer.dopt-hints-item__footerFooter containing back and next buttons
completeButton.dopt-hints-item__complete-buttonComplete button
dismissAllButton.dopt-hints-item__dismiss-all-buttonDismiss all button

Popover position

NameSelectorDescription
top.dopt-hints-item--topPositioned top
top[data-position="top"]Positioned top
right.dopt-hints-item--rightPositioned right
right[data-position="right"]Positioned right
bottom.dopt-hints-item--bottomPositioned bottom
bottom[data-position="bottom"]Positioned bottom
left.dopt-hints-item--leftPositioned left
left[data-position="left"]Positioned left

Popover alignment

NameSelectorDescription
start.dopt-hints-item--startAligned start
start[data-alignment="start"]Aligned start
center.dopt-hints-item--centerAligned center
center[data-alignment="center"]Aligned center
end.dopt-hints-item--endAligned end
end[data-alignment="end"]Aligned end

Headless hooks

If you are planning to only use the hints headlessly, you can import the hooks alone using @dopt/react-hints/hooks.

useHints

  • useHints(id: string): Hints

A React hook for accessing and updating a hints's state.

import { useHints } from '@dopt/react-hints';

export function MyHintsStep() {
const {
id,
items,
active,
completed,
dismissed,
complete,
dismiss,
filter,
count,
size,
} = useHints('onboarding-hints.hints-component');

return (
<div>
<div id="states">
<div>hints.active: {active}</div>
<div>hints.completed: {completed}</div>
<div>hints.dismissed: {dismissed}</div>
</div>
<div id="actions">
<button onClick={complete}>Complete</button>
<button onClick={dismiss}>Dismiss</button>
</div>
<div id="children">
hints.items: {items.map((item) => item.id).join(' ')}
</div>
<div id="filtering">
<div id="active-items">
{filter('active')
.map((item) => item.id)
.join(' ')}
</div>
<div id="not-active-items">
{filter('not-active')
.map((item) => item.id)
.join(' ')}
</div>
<div id="completed-items">
{filter('completed')
.map((item) => item.id)
.join(' ')}
</div>
<div id="not-completed-items">
{filter('not-completed')
.map((item) => item.id)
.join(' ')}
</div>
<div id="dismissed-items">
{filter('dismissed')
.map((item) => item.id)
.join(' ')}
</div>
<div id="not-dismissed-items">
{filter('not-dismissed')
.map((item) => item.id)
.join(' ')}
</div>
<div id="done-items">
{filter('done')
.map((item) => item.id)
.join(' ')}
</div>
<div id="not-done-items">
{filter('not-done')
.map((item) => item.id)
.join(' ')}
</div>
</div>
<div id="metadata">
<div>hints.size: {size}</div>
</div>
</div>
);
}

useHintsItem

A React hook for accessing and updating a hints item's state and content.

import { useHintsItem } from '@dopt/react-hints';
import RichText from '@dopt/react-rich-text';

export function Application() {
const {
id,
hints,
title,
body,
completeLabel,
dismissAllLabel,
active,
completed,
dismissed,
next,
back,
} = useHintsItem('onboarding-hints.step-1');

return (
<div>
<div id="states">
<div>hintsItem.active: {active}</div>
<div>hintsItem.completed: {completed}</div>
<div>hintsItem.dismissed: {dismissed}</div>
</div>
<div id="actions">
<button onClick={next}>{completeLabel}</button>
<button onClick={back}>{dismissAllLabel}</button>
</div>
<div id="content">
<div>hintsItem.title: {title}</div>
<div>
hintsItem.body: <RichText>{body}</RichText>
</div>
<div>hintsItem.completeLabel: {completeLabel}</div>
<div>hintsItem.dismissAllLabel: {dismissAllLabel}</div>
</div>
<div id="parent">
<div>hintsItem.hints: {hints?.id}</div>
</div>
</div>
);
}

Types

Hints

A stateful container for hints items.

interface Hints {
id: string;

items: HintsItem[];

active: boolean;

completed: boolean;
dismissed: boolean;

field: <V>(name: string) => undefined | null | V;

complete: () => void;
dismiss: () => void;

size: number;

filter(on: FilterableField): HintsItem[];
count(where: CountableField): number;
}

HintsItem

A child of the hints. Includes state accessors and methods for updating state along with content configured in Dopt.

interface HintsItem {
id: string;

hints: Hints | undefined;

index: number | null | undefined;

title: string | null | undefined;
body: RichText | null | undefined;

completeLabel: string | null | undefined;
dismissAllLabel: string | null | undefined;

active: boolean;

completed: boolean;
dismissed: boolean;

field: <V>(name: string) => undefined | null | V;

complete: () => void;
dismiss: () => void;
}

FilterableField

type FilterableField = 'completed' | 'not-completed' | 'dismissed' | 'not-dismissed' | 'active' | 'not-active' | 'done' | 'not-done';

CountableField

type CountableField = FilterableField;

Alignment

type Alignment = 'start' | 'center' | 'end';

Position

type Side = 'top' | 'right' | 'bottom' | 'left';