select option

Samples' Guidelines

Guidelines on how to build samples for ink's multiple environments



The ink ecosystem contains multiple environments utilizing the same samples. Each environment serves a different purpose but every sample adheres to ink's best practices. Samples are often served as ink guidelines or implementation references so we must keep them updated and organized.

All samples are contained in a samples.js file in each component's folder and follow this format:

group: 'Component',
name: 'Sample name must be unique',
description: 'Relevant information', // optional
environments: ['docs', 'expose', 'playroom'], // at least one
code: `</>`

Best practices

Each sample should test and isolate an idea so we can prove weather or not it works

  1. Follow UX Writing guidelines when adding copy. Prefer to show real language over lorem ipsum filler.
  2. Don't duplicate existing content. Samples should work across as many environments as possible but be mindful of each environment's purpose in relation to the sample.
  3. Keep it lean and use only the relevant props needed to achieve the sample's goal

Naming samples

  • All sample name should be unique, human readable and accurately describe the sample
    • Example: Selectable rows
  • Variations and states should be appended if applicable
    • Example: Selectable rows, using helpers
  • Add a description if clarity is needed, similar to a code comment
  • Avoid backticks and excessive punctuation as it can break environments like backstop

Ordering samples

Samples should be displayed starting from the most basic use cases, up to the most complex

  1. The first sample should be the most basic. If we drop the component on a page as is with only required props, what does that look like? (default use case)
  2. Add samples for each visual variation (variants, common use cases, patterns)
  3. Add contextual samples for docs (recipes)
  4. Add regression samples for common use cases with other components
  5. Add legacy regression samples if deprecation isn't complete. We still need to ensure we've covered our ground even though it's on the way out.

Bug reports

Bugs reported to us (such as from the #ink channel) but were not regressed prior, should always have a sample added. We don't know all the use cases of how our users want to use our components but as we discover them, we should regress them to ensure that they don't reappear when we make other changes.

Environment options

At least one environment is required

environments: ["docs", "expose", "playroom"]; // compiled
environments: ["plain-text"]; // not compiled


The ink documentation is our source of truth. Samples here are meant to showcase their intended usage. ALL samples here should be sharable snippets as we often send them in the #ink channel to answer questions.

  • Make it easy for our engineers to understand implementation details
    • Elaborate with description where relevant
  • Add recipes as contextual samples to highlight common patterns
    • Use solidBackground: true as an alternative to the transparent background in order to reflect our production environment when applicable

Don't add samples that we wouldn't encourage the use of such as legacy props or visuals. Those only need to be regressed in Exposé.


These are snippet meant to be embedded in our docs' usage guidelines. The formatting for these don't have to adhere to any particular standard as they aren't compiled.


The Exposé is used for both automated visual regression (via BackstopJS) and/or integration testing (via Cypress)

  • All samples displayed in docs or playroom must also appear in expose
  • Edge cases, uncommon use cases, legacy cases belong to expose only
  • Prepend Visual regression to the sample name if the sample is added specifically for BackstopJS

Check our readme for backstop for the full details. In short, samples are automatically included as a snapshot in the initial loading state via BackstopJS. Additional snapshots are added for interactive visuals such as dropdown or twiddle states (opened/closed). Snapshots can be skipped only if:

  • The test is flaky
    • with skipFlakyBackstop: true
  • The initial testing state is irrelevant
    • with skipInitialBackstop: true


The Playroom is our prototyping tool of choice especially useful for sharing mocks and/or debugging. Check out our Playroom 101 guide.

  • Contextual samples don't belong in playroom
  • Only the most common use cases need to be included with playroom. We don't want to pollute the quick add search! Also, all doc samples can be moved to playroom from the docs.
  • Don't create overly complex samples, although rare, it can freeze the editor



Check our readme for Cypress for the full details. Although not an environment option, the samples in our Exposé are also used for integration testing. We want to assert that the interactive behavior is as the user would expect.

  • Don't test if a component renders (React does this)
  • Don't test if the component color is "X" (Backstop does this)


Explorer is an experimental tool we added to allow our non-technical users to interact and experiment with props in real time while providing immediate visual feedback. It's similar to playroom but different as it doesn't require any coding knowledge.

Options are set in a PropData.js file in each component's folder and follow this format:

module.exports = [
name: "prop",
knobGroup: "group if applicable",
knobIgnore: boolean,
ignoredProp: boolean, // optional
  • Include as many pre-defined props as possible without introducing bad use cases
  • Some components (like Box or VStack) require children to show how a component renders visually
  • Components that require a parent or includes a state, won't work (because we haven't implemented it)
    • Add @skipexplorer true to the jsdoc strings in the component's main .tsx file

Typeahead skipexplorer example

Is this page helpful?