Onboarding (spotlight)
An onboarding spotlight introduces new features to users through focused messages or multi-step tours.Deprecated
This package is deprecated. Use @atlaskit/spotlight.
Default
To implement a spotlight, you should first wrap your screen or app in a SpotlightManager. Where
you want to place a spotlight, import Spotlight, SpotlightTarget and SpotlightTransition.
SpotlightTransition will handle the animation of spotlights as they render in. It should wrap any
Spotlight components. SpotlightTarget should wrap your spotlight target.
import React, { useState } from 'react';
import Button from '@atlaskit/button/default/button';
import IconButton from '@atlaskit/button/icon/button';
import CommentAddIcon from '@atlaskit/icon/core/comment-add';
import {
Spotlight,
SpotlightManager,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
import { token } from '@atlaskit/tokens';
const SpotlightTourExample = (): React.JSX.Element => {
const [isSpotlightActive, setIsSpotlightActive] = useState(false);
const start = () => setIsSpotlightActive(true);
const end = () => setIsSpotlightActive(false);
return (
<SpotlightManager>
<SpotlightTarget name="comment">
<IconButton icon={CommentAddIcon} label="comment" />
</SpotlightTarget>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<div style={{ marginTop: token('space.200') }}>
<Button appearance="primary" onClick={() => start()}>
Show example spotlight
</Button>
</div>
<SpotlightTransition>
{isSpotlightActive && (
<Spotlight
actions={[
{
onClick: () => end(),
text: 'OK',
},
]}
heading="Add a comment"
target="comment"
key="comment"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
Quickly add a comment to the work item.
</Spotlight>
)}
</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightTourExample;Tours
You can connect spotlights in multi-step onboarding tours. Only one spotlight should be shown at a time.
import React, { useState } from 'react';
import ButtonGroup from '@atlaskit/button/button-group';
import Button from '@atlaskit/button/default/button';
import IconButton from '@atlaskit/button/icon/button';
import CommentAddIcon from '@atlaskit/icon/core/comment-add';
import CopyIcon from '@atlaskit/icon/core/copy';
import {
Spotlight,
SpotlightManager,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
import { token } from '@atlaskit/tokens';
const SpotlightTourExample = (): React.JSX.Element => {
const [activeSpotlight, setActiveSpotlight] = useState<null | number>(null);
const start = () => setActiveSpotlight(0);
const next = () => setActiveSpotlight((activeSpotlight || 0) + 1);
const back = () => setActiveSpotlight((activeSpotlight || 1) - 1);
const end = () => setActiveSpotlight(null);
const renderActiveSpotlight = () => {
const spotlights = [
<Spotlight
actions={[
{
onClick: () => next(),
text: 'Next',
},
{ onClick: () => end(), text: 'Dismiss', appearance: 'subtle' },
]}
heading="Add a comment"
target="comment"
key="comment"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
Quickly add a comment to the work item.
</Spotlight>,
<Spotlight
actions={[
{ onClick: () => end(), text: 'OK' },
{ onClick: () => back(), text: 'Go back', appearance: 'subtle' },
]}
heading="Copy code"
target="copy"
key="copy"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
Trying to bring one of our components into your project? Click to copy the example code,
then go ahead paste it in your editor.
</Spotlight>,
];
if (activeSpotlight === null) {
return null;
}
return spotlights[activeSpotlight];
};
return (
<SpotlightManager>
<ButtonGroup label="Choose spotlight options">
<SpotlightTarget name="comment">
<IconButton icon={CommentAddIcon} label="comment" />
</SpotlightTarget>
<SpotlightTarget name="copy">
<IconButton icon={CopyIcon} label="Copy" />
</SpotlightTarget>
</ButtonGroup>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<div style={{ marginTop: token('space.200') }}>
<Button appearance="primary" onClick={() => start()}>
Start example tour
</Button>
</div>
<SpotlightTransition>{renderActiveSpotlight()}</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightTourExample;Blanket tint
If you prefer the spotlight to appear without the tinted blanket background, set the
blanketIsTinted prop to false on the SpotlightManager component.
import React, { useState } from 'react';
import Button from '@atlaskit/button/default/button';
import IconButton from '@atlaskit/button/icon/button';
import CommentAddIcon from '@atlaskit/icon/core/comment-add';
import {
Spotlight,
SpotlightManager,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
import { token } from '@atlaskit/tokens';
const SpotlightBlanketIsTintedExample = (): React.JSX.Element => {
const [isSpotlightActive, setIsSpotlightActive] = useState(false);
const start = () => setIsSpotlightActive(true);
const end = () => setIsSpotlightActive(false);
return (
<SpotlightManager blanketIsTinted={false}>
<SpotlightTarget name="comment">
<IconButton icon={CommentAddIcon} label="comment" />
</SpotlightTarget>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<div style={{ marginTop: token('space.200') }}>
<Button appearance="primary" onClick={() => start()}>
Show example spotlight
</Button>
</div>
<SpotlightTransition>
{isSpotlightActive && (
<Spotlight
actions={[
{
onClick: () => end(),
text: 'OK',
},
]}
heading="Add a comment"
target="comment"
key="comment"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
Quickly add a comment to the work item.
</Spotlight>
)}
</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightBlanketIsTintedExample;Actions
Appearance
You can change the default action button appearance to subtle or subtle-link with the
appearance property on the action object. Spotlights should have only one default action that
leads people through the onboarding process or prompts an action, with other actions such as "Skip"
using the subtle appearance.
import React, { useState } from 'react';
import Button from '@atlaskit/button/default/button';
import IconButton from '@atlaskit/button/icon/button';
import SearchIcon from '@atlaskit/icon/core/search';
import {
Spotlight,
SpotlightManager,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
import { token } from '@atlaskit/tokens';
const SpotlightActionsAppearance = (): React.JSX.Element => {
const [isSpotlightActive, setIsSpotlightActive] = useState(false);
const start = () => setIsSpotlightActive(true);
const end = () => setIsSpotlightActive(false);
return (
<SpotlightManager>
<SpotlightTarget name="action-button-appearances">
<IconButton icon={SearchIcon} label="Example" />
</SpotlightTarget>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<div style={{ marginTop: token('space.200') }}>
<Button appearance="primary" onClick={() => start()}>
Show example spotlight
</Button>
</div>
<SpotlightTransition>
{isSpotlightActive && (
<Spotlight
actions={[
{ onClick: () => end(), text: 'Default' },
{
appearance: 'subtle',
onClick: () => end(),
text: 'Subtle',
},
{
appearance: 'subtle-link',
onClick: () => end(),
text: 'Subtle link',
},
]}
heading="Action button appearances"
key="action-button-appearances"
target="action-button-appearances"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
You can change the default action button appearance to `subtle` or `subtle-link`.
</Spotlight>
)}
</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightActionsAppearance;Actions before element
To add a left-aligned element before the action buttons, use the actionsBeforeElement prop. One
use case for this is adding a step number to an onboarding tour with 3 or more steps.
import React, { useState } from 'react';
import ButtonGroup from '@atlaskit/button/button-group';
import Button from '@atlaskit/button/default/button';
import IconButton from '@atlaskit/button/icon/button';
import CommentAddIcon from '@atlaskit/icon/core/comment-add';
import CopyIcon from '@atlaskit/icon/core/copy';
import FullscreenEnterIcon from '@atlaskit/icon/core/fullscreen-enter';
import {
Spotlight,
SpotlightManager,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
import { token } from '@atlaskit/tokens';
const SpotlightActionsBefore = (): React.JSX.Element => {
const [activeSpotlight, setActiveSpotlight] = useState<null | number>(null);
const start = () => setActiveSpotlight(0);
const next = () => setActiveSpotlight((activeSpotlight || 0) + 1);
const back = () => setActiveSpotlight((activeSpotlight || 1) - 1);
const end = () => setActiveSpotlight(null);
const renderActiveSpotlight = () => {
const spotlights = [
<Spotlight
actionsBeforeElement="1/3"
actions={[
{
onClick: () => next(),
text: 'Next',
},
{ onClick: () => end(), text: 'Dismiss', appearance: 'subtle' },
]}
heading="Add a comment"
target="comment"
key="comment"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
Quickly add a comment to the work item.
</Spotlight>,
<Spotlight
actionsBeforeElement="2/3"
actions={[
{ onClick: () => next(), text: 'Next' },
{ onClick: () => back(), text: 'Go back', appearance: 'subtle' },
{ onClick: () => end(), text: 'Dismiss', appearance: 'subtle' },
]}
heading="Copy code"
target="copy"
key="copy"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
Trying to bring one of our components into your project? Click to copy the example code,
then go ahead paste it in your editor.
</Spotlight>,
<Spotlight
actionsBeforeElement="3/3"
actions={[
{ onClick: () => end(), text: 'OK' },
{ onClick: () => back(), text: 'Go back', appearance: 'subtle' },
]}
heading="Expand to full screen"
target="expand"
key="expand"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
For a focused view of the example, you can expand to full screen.
</Spotlight>,
];
if (activeSpotlight === null) {
return null;
}
return spotlights[activeSpotlight];
};
return (
<SpotlightManager>
<ButtonGroup label="Choose spotlight options">
<SpotlightTarget name="comment">
<IconButton icon={CommentAddIcon} label="comment" />
</SpotlightTarget>
<SpotlightTarget name="copy">
<IconButton icon={CopyIcon} label="Copy" />
</SpotlightTarget>
<SpotlightTarget name="expand">
<IconButton icon={FullscreenEnterIcon} label="Full screen" />
</SpotlightTarget>
</ButtonGroup>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<div style={{ marginTop: token('space.200') }}>
<Button appearance="primary" onClick={() => start()}>
Start example tour
</Button>
</div>
<SpotlightTransition>{renderActiveSpotlight()}</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightActionsBefore;Heading
To add a heading to a spotlight, use the heading prop. For content guidance, see the
usage tab.
Heading after element
The headingAfterElement prop allows you to place an element to the right of the heading. This is
sometimes used to implement a close icon button in a spotlight.
import React, { useState } from 'react';
import Button from '@atlaskit/button/default/button';
import IconButton from '@atlaskit/button/icon/button';
import CommentAddIcon from '@atlaskit/icon/core/comment-add';
import CrossIcon from '@atlaskit/icon/core/cross';
import {
Spotlight,
SpotlightManager,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
import { token } from '@atlaskit/tokens';
const SpotlightHeadingAfterElement = (): React.JSX.Element => {
const [isSpotlightActive, setIsSpotlightActive] = useState(false);
const start = () => setIsSpotlightActive(true);
const end = () => setIsSpotlightActive(false);
return (
<SpotlightManager>
<SpotlightTarget name="comment">
<IconButton icon={CommentAddIcon} label="comment" />
</SpotlightTarget>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<div style={{ marginTop: token('space.200') }}>
<Button appearance="primary" onClick={() => start()}>
Show example spotlight
</Button>
</div>
<SpotlightTransition>
{isSpotlightActive && (
<Spotlight
headingAfterElement={
<IconButton
icon={CrossIcon}
appearance="subtle"
onClick={() => end()}
label="Close"
/>
}
actions={[
{
onClick: () => end(),
text: 'OK',
},
]}
heading="Add a comment"
target="comment"
key="comment"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
Quickly add a comment to the work item.
</Spotlight>
)}
</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightHeadingAfterElement;Image
You can add an image to a spotlight with the image prop. Most Atlassian illustrations are designed
to work with neutral backgrounds, so you may need brand design support to implement an ideal
spotlight image.
import React, { useState } from 'react';
import Button from '@atlaskit/button/default/button';
import {
Spotlight,
SpotlightManager,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
import { token } from '@atlaskit/tokens';
import spotlightImage from '../assets/this-is-new-jira.png';
const SpotlightImageExample = (): React.JSX.Element => {
const [isSpotlightActive, setIsSpotlightActive] = useState(false);
const start = () => setIsSpotlightActive(true);
const end = () => setIsSpotlightActive(false);
return (
<SpotlightManager>
<SpotlightTarget name="switch">
<Button>Switch projects</Button>
</SpotlightTarget>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<div style={{ marginTop: token('space.200') }}>
<Button appearance="primary" onClick={() => start()}>
Show example spotlight
</Button>
</div>
<SpotlightTransition>
{isSpotlightActive && (
<Spotlight
image={spotlightImage}
actions={[
{
onClick: () => end(),
text: 'OK',
},
]}
target="switch"
label="Switch projects"
key="switch"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
Select the project name and icon to quickly switch between your most recent projects.
</Spotlight>
)}
</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightImageExample;Pulse
When spotlights are active, a pulsing outline helps draw attention to the target. It's possible for you to use this spotlight pulse in custom ways. For example, you can apply the pulse on the target element before the spotlight is active, and trigger the spotlight the first time a person interacts with it.
import React, { useState } from 'react';
import ButtonGroup from '@atlaskit/button/button-group';
import Button from '@atlaskit/button/default/button';
import {
Spotlight,
SpotlightManager,
SpotlightPulse,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
const SpotlightPulseExample = (): React.JSX.Element => {
const [isSpotlightActive, setIsSpotlightActive] = useState(false);
const start = () => setIsSpotlightActive(true);
const end = () => setIsSpotlightActive(false);
return (
<SpotlightManager>
<ButtonGroup label="Choose spotlight options">
<SpotlightTarget name="new">
<SpotlightPulse radius={3} pulse={isSpotlightActive ? false : true}>
<Button onClick={() => start()}>New feature</Button>
</SpotlightPulse>
</SpotlightTarget>
<SpotlightTarget name="copy">
<Button>Existing feature</Button>
</SpotlightTarget>
</ButtonGroup>
<SpotlightTransition>
{isSpotlightActive && (
<Spotlight
actions={[
{
onClick: () => end(),
text: 'OK',
},
]}
heading="Spotlight pulse"
target="new"
key="new"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
Announcing new features with a spotlight pulse is an onboarding pattern that you can
explore.
</Spotlight>
)}
</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightPulseExample;Turning off the pulse
You can turn off the pulsing animation by setting the pulse prop to false.
import React, { useState } from 'react';
import ButtonGroup from '@atlaskit/button/button-group';
import Button from '@atlaskit/button/default/button';
import {
Spotlight,
SpotlightManager,
SpotlightPulse,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
const SpotlightPulseExample = (): React.JSX.Element => {
const [isSpotlightActive, setIsSpotlightActive] = useState(false);
const start = () => setIsSpotlightActive(true);
const end = () => setIsSpotlightActive(false);
return (
<SpotlightManager>
<ButtonGroup label="Choose spotlight options">
<SpotlightTarget name="new">
<SpotlightPulse radius={3} pulse={false}>
<Button onClick={() => start()}>New feature</Button>
</SpotlightPulse>
</SpotlightTarget>
<SpotlightTarget name="copy">
<Button>Existing feature</Button>
</SpotlightTarget>
</ButtonGroup>
<SpotlightTransition>
{isSpotlightActive && (
<Spotlight
actions={[
{
onClick: () => end(),
text: 'OK',
},
]}
heading="Spotlight pulse"
target="new"
key="new"
targetRadius={3}
targetBgColor={'#FFFFFF'}
pulse={false}
>
Announcing new features with a spotlight pulse is an onboarding pattern that you can
explore.
</Spotlight>
)}
</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightPulseExample;Dialog placement
By default, a spotlight dialog will be positioned to the "bottom left" relative to the target. You
can change this by setting your desired position in the dialogPlacement prop.
import React, { useState } from 'react';
import Button from '@atlaskit/button/standard-button';
import CrossIcon from '@atlaskit/icon/core/cross';
import {
Spotlight,
SpotlightManager,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
import { token } from '@atlaskit/tokens';
type Placement = (typeof options)[number];
const options = [
'top right',
'top center',
'top left',
'right bottom',
'right middle',
'right top',
'bottom left',
'bottom center',
'bottom right',
'left top',
'left middle',
'left bottom',
] as const;
const SpotlightDialogPlacement = (): React.JSX.Element => {
const [isSpotlightActive, setIsSpotlightActive] = useState(false);
const [dialogPlacement, setDialogPlacement] = useState(0);
const start = () => setIsSpotlightActive(true);
const end = () => setIsSpotlightActive(false);
const shiftPlacementOption = () => {
if (dialogPlacement !== options.length - 1) {
return setDialogPlacement(dialogPlacement + 1);
}
return setDialogPlacement(0);
};
const placement = options[dialogPlacement];
return (
<SpotlightManager>
<SpotlightTarget name="placement">
<Button>Example target</Button>
</SpotlightTarget>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<div style={{ marginTop: token('space.200') }}>
<Button appearance="primary" onClick={() => start()}>
Show example spotlight
</Button>
</div>
<SpotlightTransition>
{isSpotlightActive ? (
<Spotlight
heading={`Dialog placement: ${placement}`}
headingAfterElement={
<Button
iconBefore={<CrossIcon label="Close" color={token('color.icon.inverse')} />}
onClick={() => end()}
/>
}
actions={[
{
onClick: () => shiftPlacementOption(),
text: 'Shift dialog placement',
},
]}
dialogPlacement={placement as Placement}
target="placement"
key="placement"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
You can set where the dialog should appear relative to the contents of the children. Try
out the options by clicking the action below.
</Spotlight>
) : null}
</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightDialogPlacement;Dialog width
You can set a dialog width for a spotlight dialog with the dialogWidth prop. The minimum supported
width is 160px, and the maximum is 600px.
import React, { useState } from 'react';
import ButtonGroup from '@atlaskit/button/button-group';
import Button from '@atlaskit/button/default/button';
import IconButton from '@atlaskit/button/icon/button';
import CommentAddIcon from '@atlaskit/icon/core/comment-add';
import CopyIcon from '@atlaskit/icon/core/copy';
import FullscreenEnterIcon from '@atlaskit/icon/core/fullscreen-enter';
import {
Spotlight,
SpotlightManager,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
import { token } from '@atlaskit/tokens';
const SpotlightDialogWidth = (): React.JSX.Element => {
const [activeSpotlight, setActiveSpotlight] = useState<null | number>(null);
const start = () => setActiveSpotlight(0);
const next = () => setActiveSpotlight((activeSpotlight || 0) + 1);
const back = () => setActiveSpotlight((activeSpotlight || 1) - 1);
const end = () => setActiveSpotlight(null);
const renderActiveSpotlight = () => {
const spotlights = [
<Spotlight
dialogWidth={600}
actionsBeforeElement="1/3"
actions={[
{
onClick: () => next(),
text: 'Next',
},
{ onClick: () => end(), text: 'Dismiss', appearance: 'subtle' },
]}
heading="Add a comment"
target="comment"
key="comment"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
Quickly add a comment to the work item.
</Spotlight>,
<Spotlight
dialogWidth={400}
actionsBeforeElement="2/3"
actions={[
{ onClick: () => next(), text: 'Next' },
{ onClick: () => back(), text: 'Go back', appearance: 'subtle' },
{ onClick: () => end(), text: 'Dismiss', appearance: 'subtle' },
]}
heading="Copy code"
target="copy"
key="copy"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
Trying to bring one of our components into your project? Click to copy the example code,
then go ahead paste it in your editor.
</Spotlight>,
<Spotlight
dialogWidth={250}
actionsBeforeElement="3/3"
actions={[
{ onClick: () => end(), text: 'OK' },
{ onClick: () => back(), text: 'Go back', appearance: 'subtle' },
]}
heading="Expand to full screen"
target="expand"
key="expand"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
For a focused view of the example, you can expand to full screen.
</Spotlight>,
];
if (activeSpotlight === null) {
return null;
}
return spotlights[activeSpotlight];
};
return (
<SpotlightManager>
<ButtonGroup label="Choose spotlight options">
<SpotlightTarget name="comment">
<IconButton icon={CommentAddIcon} label="comment" />
</SpotlightTarget>
<SpotlightTarget name="copy">
<IconButton icon={CopyIcon} label="Copy" />
</SpotlightTarget>
<SpotlightTarget name="expand">
<IconButton icon={FullscreenEnterIcon} label="Full screen" />
</SpotlightTarget>
</ButtonGroup>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<div style={{ marginTop: token('space.200') }}>
<Button appearance="primary" onClick={() => start()}>
Start example tour
</Button>
</div>
<SpotlightTransition>{renderActiveSpotlight()}</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightDialogWidth;Target border radius
The border radius of the spotlight target needs to be explicitly set. In the next example, the first
spotlight applies the default behavior, the second spotlight sets targetRadius to 3 to match a
target button, and the final spotlight has targetRadius to 24 to match a round target.
import React, { useState } from 'react';
import Avatar from '@atlaskit/avatar/avatar';
import ButtonGroup from '@atlaskit/button/button-group';
import Button from '@atlaskit/button/default/button';
import IconButton from '@atlaskit/button/icon/button';
import CommentAddIcon from '@atlaskit/icon/core/comment-add';
import CopyIcon from '@atlaskit/icon/core/copy';
import {
Spotlight,
SpotlightManager,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
import { token } from '@atlaskit/tokens';
const SpotlightTargetRadius = (): React.JSX.Element => {
const [activeSpotlight, setActiveSpotlight] = useState<null | number>(null);
const start = () => setActiveSpotlight(0);
const next = () => setActiveSpotlight((activeSpotlight || 0) + 1);
const back = () => setActiveSpotlight((activeSpotlight || 1) - 1);
const end = () => setActiveSpotlight(null);
const renderActiveSpotlight = () => {
const spotlights = [
<Spotlight
actions={[
{
onClick: () => next(),
text: 'Next',
},
{ onClick: () => end(), text: 'Dismiss', appearance: 'subtle' },
]}
heading="Add a comment"
target="comment"
key="comment"
targetBgColor={'#FFFFFF'}
>
Quickly add a comment to the work item.
</Spotlight>,
<Spotlight
targetRadius={3}
actions={[
{ onClick: () => next(), text: 'Next' },
{ onClick: () => back(), text: 'Go back', appearance: 'subtle' },
{ onClick: () => end(), text: 'Dismiss', appearance: 'subtle' },
]}
heading="Copy code"
target="copy"
key="copy"
targetBgColor={'#FFFFFF'}
>
Trying to bring one of our components into your project? Click to copy the example code,
then go ahead paste it in your editor.
</Spotlight>,
<Spotlight
targetRadius={24}
actions={[
{ onClick: () => end(), text: 'OK' },
{ onClick: () => back(), text: 'Go back', appearance: 'subtle' },
]}
heading="Upload a profile picture"
target="avatar"
key="avatar"
targetBgColor={'#FFFFFF'}
>
Having a profile picture helps you and your team by making your contributions more
identifiable. If you'd rather remain mysterious, that's okay too! You do you.
</Spotlight>,
];
if (activeSpotlight === null) {
return null;
}
return spotlights[activeSpotlight];
};
return (
<SpotlightManager>
<ButtonGroup label="Choose spotlight options">
<SpotlightTarget name="comment">
<IconButton icon={CommentAddIcon} label="comment" />
</SpotlightTarget>
<SpotlightTarget name="copy">
<IconButton icon={CopyIcon} label="Copy" />
</SpotlightTarget>
</ButtonGroup>
<SpotlightTarget name="avatar">
<Avatar />
</SpotlightTarget>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<div style={{ marginTop: token('space.200') }}>
<Button appearance="primary" onClick={() => start()}>
Start example tour
</Button>
</div>
<SpotlightTransition>{renderActiveSpotlight()}</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightTargetRadius;Target background color
Sometimes the blanket can affect the background color of the target element. For example, subtle
buttons are semi-transparent, which causes them to look darker when the blanket is applied. In cases
like this, you can pass a color value to targetBgColor to make your target stand out properly.
import React, { useState } from 'react';
import ButtonGroup from '@atlaskit/button/button-group';
import Button from '@atlaskit/button/default/button';
import IconButton from '@atlaskit/button/icon/button';
import CommentAddIcon from '@atlaskit/icon/core/comment-add';
import CopyIcon from '@atlaskit/icon/core/copy';
import {
Spotlight,
SpotlightManager,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
import { token } from '@atlaskit/tokens';
const SpotlightTargetBackground = (): React.JSX.Element => {
const [activeSpotlight, setActiveSpotlight] = useState<null | number>(null);
const start = () => setActiveSpotlight(0);
const next = () => setActiveSpotlight((activeSpotlight || 0) + 1);
const back = () => setActiveSpotlight((activeSpotlight || 1) - 1);
const end = () => setActiveSpotlight(null);
const renderActiveSpotlight = () => {
const spotlights = [
<Spotlight
actions={[
{
onClick: () => next(),
text: 'Next',
},
{ onClick: () => end(), text: 'Dismiss', appearance: 'subtle' },
]}
heading="No targetBgColor set"
target="comment"
key="comment"
targetRadius={3}
>
You can see that even though the spotlight pulse surrounds the button, it no longer stands
out on the page.
</Spotlight>,
<Spotlight
targetBgColor={'#FFFFFF'}
actions={[
{ onClick: () => end(), text: 'OK' },
{ onClick: () => back(), text: 'Go back', appearance: 'subtle' },
]}
heading="With targetBg set"
target="copy"
key="copy"
targetRadius={3}
>
Setting the `targetBgColor` ensures that the cloned spotlight target has all the context it
needs to stand out properly.
</Spotlight>,
];
if (activeSpotlight === null) {
return null;
}
return spotlights[activeSpotlight];
};
return (
<SpotlightManager>
<ButtonGroup label="Choose spotlight options">
<SpotlightTarget name="comment">
<IconButton icon={CommentAddIcon} label="comment" />
</SpotlightTarget>
<SpotlightTarget name="copy">
<IconButton icon={CopyIcon} label="Copy" />
</SpotlightTarget>
</ButtonGroup>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<div style={{ marginTop: token('space.200') }}>
<Button appearance="primary" onClick={() => start()}>
Start example tour
</Button>
</div>
<SpotlightTransition>{renderActiveSpotlight()}</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightTargetBackground;Target replacement
You can replace the original target with another component using the targetReplacement prop.

import { type ImgHTMLAttributes, useState } from 'react';
import { css, jsx } from '@compiled/react';
import Button from '@atlaskit/button/default/button';
import {
Spotlight,
SpotlightManager,
SpotlightPulse,
SpotlightTarget,
SpotlightTransition,
} from '@atlaskit/onboarding';
import { token } from '@atlaskit/tokens';
import logoInverted from '../assets/logo-inverted.png';
import logo from '../assets/logo.png';
const Replacement = (rect: any) => {
const style = { overflow: 'hidden', ...rect };
return (
<SpotlightPulse style={style}>
<Image alt="I replace the target element." src={logoInverted} />
</SpotlightPulse>
);
};
const imageStyles = css({
width: '128px',
height: '128px',
});
const Image = ({ alt, src }: ImgHTMLAttributes<HTMLImageElement>) => (
<img src={src} alt={alt} css={imageStyles} />
);
const SpotlightTargetReplacementExample = (): JSX.Element => {
const [isSpotlightActive, setIsSpotlightActive] = useState(false);
const start = () => setIsSpotlightActive(true);
const end = () => setIsSpotlightActive(false);
return (
<SpotlightManager>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<img alt="hidden" src={logoInverted} style={{ display: 'none' }} />
<SpotlightTarget name="target-replacement-example">
<Image alt="I will be replaced..." src={logo} />
</SpotlightTarget>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<div style={{ marginTop: token('space.200') }}>
<Button appearance="primary" onClick={() => start()}>
Show example spotlight
</Button>
</div>
<SpotlightTransition>
{isSpotlightActive && (
<Spotlight
targetReplacement={Replacement}
actions={[{ onClick: () => end(), text: 'OK' }]}
dialogPlacement="bottom left"
key="target-replacement-example"
heading="Target replacement"
target="target-replacement-example"
targetRadius={3}
>
You can replace the original target with another component using the `targetReplacement`
prop.
</Spotlight>
)}
</SpotlightTransition>
</SpotlightManager>
);
};
export default SpotlightTargetReplacementExample;Conditional spotlight targets
You can use the useSpotlight hook to check if a spotlight target is rendered or not. This allows
you to conditionally add steps into a spotlight tour.
import React, { useState } from 'react';
import ButtonGroup from '@atlaskit/button/button-group';
import Button from '@atlaskit/button/default/button';
import IconButton from '@atlaskit/button/icon/button';
import CommentAddIcon from '@atlaskit/icon/core/comment-add';
import CopyIcon from '@atlaskit/icon/core/copy';
import FullscreenEnterIcon from '@atlaskit/icon/core/fullscreen-enter';
import {
Spotlight,
SpotlightManager,
SpotlightTarget,
SpotlightTransition,
useSpotlight,
} from '@atlaskit/onboarding';
import { token } from '@atlaskit/tokens';
const SpotlightWithConditionalTargets = () => {
const [active, setActive] = useState<number | null>(null);
const [isSecondTargetVisible, setIsSecondTargetVisible] = useState(true);
const { isTargetRendered } = useSpotlight();
const start = () => setActive(0);
const next = () => setActive((active || 0) + 1);
const back = () => setActive((active || 0) - 1);
const end = () => setActive(null);
const renderActiveSpotlight = () => {
if (active == null) {
return null;
}
const spotlights = [
{
target: 'comment',
element: (
<Spotlight
actions={[
{
onClick: () => next(),
text: 'Next',
},
{ onClick: () => end(), text: 'Dismiss', appearance: 'subtle' },
]}
heading="Add a comment"
target="comment"
key="comment"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
Quickly add a comment to the work item.
</Spotlight>
),
},
{
target: 'copy',
element: (
<Spotlight
actions={[
{ onClick: () => next(), text: 'Next' },
{ onClick: () => back(), text: 'Go back', appearance: 'subtle' },
{ onClick: () => end(), text: 'Dismiss', appearance: 'subtle' },
]}
heading="Copy code"
target="copy"
key="copy"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
Trying to bring one of our components into your project? Click to copy the example code,
then go ahead paste it in your editor.
</Spotlight>
),
},
{
target: 'expand',
element: (
<Spotlight
actions={[
{ onClick: () => end(), text: 'OK' },
{ onClick: () => back(), text: 'Go back', appearance: 'subtle' },
]}
heading="Expand to full screen"
target="expand"
key="expand"
targetRadius={3}
targetBgColor={'#FFFFFF'}
>
For a focused view of the example, you can expand to full screen.
</Spotlight>
),
},
]
.filter(({ target }) => isTargetRendered(target))
.map(({ element }) => element);
return spotlights[active];
};
return (
<>
<ButtonGroup label="Choose spotlight options">
<SpotlightTarget name="comment">
<IconButton icon={CommentAddIcon} label="comment" />
</SpotlightTarget>
{isSecondTargetVisible && (
<SpotlightTarget name="copy">
<IconButton icon={CopyIcon} label="Copy" />
</SpotlightTarget>
)}
<SpotlightTarget name="expand">
<IconButton icon={FullscreenEnterIcon} label="Full screen" />
</SpotlightTarget>
</ButtonGroup>
{/* eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop -- Ignored via go/DSP-18766 */}
<div style={{ marginTop: token('space.200') }}>
<ButtonGroup label="Choose spotlight options">
<Button appearance="primary" onClick={() => start()}>
Start example tour
</Button>
<Button onClick={() => setIsSecondTargetVisible(!isSecondTargetVisible)}>
Show/hide second spotlight target
</Button>
</ButtonGroup>
</div>
<SpotlightTransition>{renderActiveSpotlight()}</SpotlightTransition>
</>
);
};
export default function SpotlightWithConditionalTargetsExample(): React.JSX.Element {
return (
<SpotlightManager>
<SpotlightWithConditionalTargets />
</SpotlightManager>
);
}