Skip to content

Product showcase

Interactive and informational sections that show the product off: a guided tour, a live theme playground, role-based solutions, integrations, release news and a comparison table.

Installation & usage

npx @youj/cli add marketing-product-tour

Also installs async-button, avatar, badge, button, icon-arrow-right, icon-check, icon-check-circle, icon-git-branch, icon-message, icon-rocket, progress, reveal, slider, switch, tabs, textarea, use-controllable-state, use-visible, youj-core, youj-presets, youj-ui-core.

The CLI copies the block to blocks/marketing/product-tour.tsx with every component it uses, so it’s yours to edit.

Every prop is optional and falls back to the demo, so it renders as you see it until you pass your own. Give it your data, rewrite or translate its strings through copy, and connect its actions:

productTour-view.tsx
'use client'

import Link from 'next/link'
import { ProductTour, type ProductTourProps } from '@/blocks/marketing/product-tour'

export function ProductTourView({ steps, done }: Pick<ProductTourProps, 'steps' | 'done'>) {
  return (
    <ProductTour
      steps={steps}
      done={done}
      copy={{ eyebrow: 'Product tour' }}
      linkComponent={Link}
      onValueChange={(value) => {
        // your code
      }}
      onDoneChange={(done) => {
        // your code
      }}
    />
  )
}

Reference

Props12 props, 2 types

Props

ProductTour props
PropType
themeThemeInput

Default: the theme around it. The showcase passes the chosen preset here.

–
embeddedboolean

A section inside another page: the host lays it out (no page background, section padding or max width).

default false

false
stepsProductTourStep[]

The steps, in order.

default the demo's connect, guardrails, review and canary

the demo's connect, guardrails, review and canary
valuestring

The open step's id, controlled.

–
defaultValuestring

The step shown first, uncontrolled.

default the first

the first
onValueChange(value: string) => void

Called with the step's id when someone opens one.

–
donestring[]

The ids of the steps done, controlled.

–
onDoneChange(done: string[]) => void

Called with the ids of the steps done, as each is completed or the tour restarted.

–
cta{ label?: string; href: string; onClick?: ComponentProps<'a'>['onClick']; }

The call to action after the last step; null hides it.

default "Start with your own project" to `#signup`

"Start with your own project" to `#signup`
linkComponentElementType

Renders the call to action: pass your router's Link.

default 'a'

'a'
copyPartial<ProductTourCopy>

Any of the block's strings, to rewrite or translate.

–
headingLevel1 | 2 | 3

The heading's level; each open step's heading sits one below.

default 2

2

ProductTourStep

ProductTourStep props
PropType
idRequiredstring–
titleRequiredstring

The step's name on the rail.

–
descriptionRequiredstring

What happens, in a sentence or two; shown under the title while the step is open.

–
promptstring

What to try ("Connect a repository"), shown over the picture as a prompt.

–
renderRequired(context: ProductTourStepContext) => ReactNode

The live picture: real components the visitor can operate. Call complete when they have done the step's thing; mark the control to try with data-yj-tour-target and a beacon points it out until then.

–

ProductTourStepContext

ProductTourStepContext props
PropType
doneRequiredboolean

Whether the visitor has done this step's thing.

–
completeRequired() => void

Call it when they do: the step gets its check and the progress moves.

–
copyRequiredProductTourCopy

The block's strings, for a step's own labels.

–
Strings18 keys for copy

Strings

copy takes any of these keys; the rest keep their defaults. A key whose text holds a value (a count, a name) takes a function.

eyebrowtitledescriptionstepsLabelstepNameprogressaddressbacknextfinishresettrystepDoneconnectRepocommentPinreplyPlaceholderreplyLabeltrafficLabel
Built from9 components
Accessibilitylandmarks, tabs, dialogs, tables

Accessibility

Every section here is a <section> named by its own heading (aria-labelledby). The heading is an h2 by default and headingLevel changes it; the pieces with items below the title (Product tour, Solutions, What’s new) set theirs one level deeper.

Product tour and Solutions are built on Tabs: the tab list is named, Left and Right Arrow move between tabs, Home and End jump to the ends, and the panel follows the selected tab. Product tour announces a finished tour in a polite status region; Solutions announces the role and industry in view the same way. Product tour’s beacon is decoration (aria-hidden, and it never takes a click): the step’s “Try it” prompt says the same in words, and under reduced motion the beacon is a still dot.

Integrations has a labelled search field, a categories nav whose buttons use aria-pressed, and a result count in a status region; its detail sheet traps focus and closes with Escape. What’s new’s area filter and Product comparison’s alternative picker and “only differences” switch are named controls, and Product comparison is a real table with visually hidden text in its cells and a labelled coverage bar. Theme playground groups its controls under a label, announces the applied recipe in a status region, and renders its preview as a decorative frame (inert) around a real page.

The links and buttons are real a and button elements with the kit’s focus ring.

App logos in the Integrations demo are trademarks of their owners, shown for illustration only.