Getting started

Contribute

How we check that a component is done.

This page is about how we check that a component is done. A Moments component is done when it passes the checks below. An engineer confirms that in the Easol app, then removes the in-review tag. Status labels, and how to change them, are on Component status.

Before you open the pull request

Complete every item. If an item doesn't apply, write why next to it.

Build

  • Figma parity. The component matches its Figma frame 1:1, across all variants, tones and sizes.
  • All states. Default, hover, pressed, focus-visible and disabled are built. Loading, error, selected, indeterminate and read-only are built where they apply.
  • Tokens and theming. The component uses only semantic or component --moments-* tokens, with no primitive tokens and no hardcoded colours or lengths. Light and dark then work with no extra code. npm run lint passes.
  • Accessibility. The component has the correct role, works by keyboard, shows a visible focus ring, and carries aria-* attributes where needed (for example aria-label on icon-only controls). Contrast meets WCAG (Web Content Accessibility Guidelines) level AA.
  • Code. The component is a Lit web component in src/<name>/moments-<name>.ts and uses CSS variables only. You do not add a line to package.json for it. That file already maps @easolhq/moments/<name> to dist/components/<name>.js (for example @easolhq/moments/button). The component build writes that file for every folder that contains moments-<name>.ts. Without it, the Easol app cannot import the component on its own.
  • Storybook. The component has two sidebar pages, Guidelines and Playground. Playground has controls and a variants-and-states overview. When the component is ready, Storybook has Playground and a Variants group, and the guidelines move to docs.easol.com, as they did for Button.
  • Visual check. Playwright opens every Storybook story, takes a screenshot, and compares it with a saved image in visual/baselines/. Those images are the baseline: the appearance already accepted. The check runs on the pull request and never fails it, so read the pull request comment, which names the stories that changed. A new component has no baseline yet. CI makes one after the merge to main. To accept a deliberate change, run Actions → Update visual baselines.
  • Naming. The naming guidelines in Standards have been followed.

Behaviour

Test these by hand on the built component. If a check obviously doesn't apply (drag, scroll or multi-select on a switch or avatar, for example), skip it. Treat the list as a menu, not a mandate.

Desktop: keyboard

  • The component is fully operable by keyboard alone: Tab, Shift+Tab, Enter and Space, arrow keys where relevant, and Escape.
  • A visible focus ring shows at every stop, and focus order matches visual order.
  • Focus behaves correctly on open and close. A modal, drawer or popover traps focus while open and returns it to the trigger on close.

Desktop: mouse

  • Hover. Enter and exit transitions work. Hover on disabled elements shows a not-allowed cursor, with no elevation or animation. The hover state survives scrolling under the cursor.
  • Click mechanics. Check whether the action fires on mousedown or on click/mouseup. This matters for anything that opens on click, because a mousedown-open can fight with a drag. Check double-click behaviour. Check right-click, including whether a custom context menu conflicts with the OS one (for example on icon-button and menu).
  • Drag. Check anything with drag semantics: drop-area (drag-over versus drop-outside), the colour-picker canvas and slider, reorderable lists and resize handles. Check the drag threshold. A small accidental mouse movement during a click must not cancel the click or start a drag.
  • Click-away and dismissal. For modal, popover, menu and drawer, check a click on the backdrop, a click on a different trigger while one is already open, and rapid re-clicks of the same trigger.
  • Scroll and wheel. Check mouse wheel versus trackpad momentum inside scrollable select and menu lists and in data-table. Check whether number-field responds to scroll-to-increment.
  • Precision and hit targets. Click at the edge of the visible bounds and compare with the real hit area, especially on icon-only buttons. Check overlapping targets, such as a clear icon inside a field against the field's own click-to-focus area.
  • Multi-select modifiers. Check shift-click, ctrl-click and cmd-click ranges in data-table and chip selection, and whether the behaviour depends on the prior selection state.
  • Cursor affordance. The cursor (pointer, default, not-allowed, grab or grabbing) matches the component's actual interactivity.
  • Hover-triggered content timing. Tooltips and popovers have sensible delay-in and delay-out. Moving the mouse from the trigger onto the hovered content keeps it open.

Mobile: touch

  • Tap targets meet the minimum size, even when the visual element is smaller.
  • No hover-only affordance is the only way to discover a control. Hover has no touch equivalent.
  • Long-press, swipe and drag gestures, if the component has any, work and don't conflict with page scroll.
  • The component works with the on-screen keyboard open. The viewport resize must not break the layout or dismiss the component.

Documentation

The page is <name>.mdx. It follows Standards.

  • Intro. One short sentence says what the component is and what it is for. The default story sits directly under it in a <Canvas>.
  • When to use. Simple bullet points, each giving a reason to use the component.
  • When not to use. Simple bullet points, each giving a reason not to use the component and naming what to use instead. Each links to that component when one exists.
  • Variants. Each property has its own section with a <Canvas> showing every value, labelled inside the component. Each section explains when to use each value and ends with Recommendations.
  • Props. <ArgTypes of={S} />, built from the argTypes in the stories file. Every property has a description, a type and, when it has one, a default. Properties that exist in Figma and not in code sit in the same table under the In Figma only category. Every section above is required, even when it has little to say.
  • Slots and events. If the component has any, the page documents them.
  • Copy. The wording is written with the clear-writing skill at .claude/skills/clear-writing/SKILL.md. For usage guidance and phrasing, look at Mews, Primer and Nordhealth.

Engineering

  • CI. Continuous integration (CI) is green: lint, the accessibility check and the build.
  • Visual baseline. You have looked at the committed baseline images.
  • Package. The built file and folder match <moments-button> and <moments-icon-button>.
  • Docs match code. The Props table lists the component's real properties.

Move it to in review

  • In the component's stories meta, change the tags line from stage 1 to stage 2. Add '!in-progress' and 'in-review':

    // before: no tags line
    // after:
    tags: ['!in-progress', 'in-review']
  • The pull request description links the Linear issue and requests review from an engineer.

  • Run npm run build-storybook, open storybook-static/index.json and confirm that both the Guidelines and Playground entries list in-review. If the Guidelines entry doesn't, tag the .mdx page directly.

If the engineer finds problems, fix each one or open a linked issue for it. The tag stays in-review until the engineer approves.

Mark it done

  • In the component's stories meta, delete 'in-review' from the tags line. Leave '!in-progress' in place.

    // before
    tags: ['!in-progress', 'in-review']
    // after
    tags: ['!in-progress']

    If you delete the whole line, the component inherits in-progress again and gets the In Progress label back.

  • Move the guidelines to docs/site/components/<group>/<name>.mdx, and split the variants into moments-<name>-variants.stories.js, as Button does.

  • Run npm run build-storybook and open storybook-static/index.json. Check that the component's Playground and Variants entries carry neither in-progress nor in-review.

On this page