Documentation

Guidelines

Our technical guidelines describes the goals and rules that contributors and we (the development team of onyx) must adhere to.

Our technical guidelines describes the goals and rules that contributors and we (the development team of onyx) must adhere to.

Copy link to headline:Global Architecture

  1. ๐Ÿ“œ onyxdoes not have direct dependencies, only a limited amount of peer- and dev-dependencies.
    • peer-dependencies: we allow a wide range of versions (e.g. >= 3).
    • We use third-party dependencies sparingly. The need for each dependency must be well justified and documented in this wiki.
  2. ๐Ÿ“œ We rely on browser / native features as much as possible.
  3. ๐Ÿ“œ Frequently used code is extracted into utils / composables.
  4. ๐Ÿ“œ We provide custom eslint rules for principles and best practices where needed.

Copy link to headline:Pull Requests

  1. ๐Ÿ“œ Every PR that affects the public API of any published npm libraries must include a changeset(opens in a new tab).
  2. ๐Ÿ“œ A PR must consist of one (preferable) or multiple self-contained changes.
  3. ๐Ÿ“œ An "Implement" ticket can and will usually be split up over multiple PRs, so a single PR doesn't have to include all feature facets.
    1. โ—๏ธ These PRs should be sliced reasonably, as a set of changes that belong together.
    2. This enables us to do faster Code Reviews.

Copy link to headline:Documentation

  1. ๐Ÿ“œ Everything we publish (features, packages, ...) must be documented
  2. ๐Ÿ“œ The documentation explains everything the users need to know and do not expect implicit knowledge. E.g. all variants that a component offers are showcased and explained when they are used
  3. ๐Ÿ“œ We have a well written changelog which includes all relevant information on the usage of the changes

Copy link to headline:Usability

  1. ๐Ÿ“œ The DX (Developer Experience) of our users is our top priority
  2. ๐Ÿ“œ We offer excellent typing support
  3. ๐Ÿ“œ We only support modern technologies (ES202x)(opens in a new tab)/ESM
  4. ๐Ÿ“œ onyxcomponents must work in the three big browser (engines): Chromium, Firefox and Safari
    • Support is limited to versions up to one year old
  5. ๐Ÿ“œ We only use Web APIs that match our browserlist

Copy link to headline:Component Interface

  1. ๐Ÿ“œ Component variants that differ in regards to their aria pattern(opens in a new tab) are separate components
  2. ๐Ÿ“œ When Prop/Attr names of the (wrapped) native element are being used for component properties,
    • they must mirror or extend the expected behavior of the native attribute
    • they may limit the natives attribute accepted values (e.g. type property of the input could be limited to only support type text and password)
  3. ๐Ÿ“œ Fallthrough attributes(opens in a new tab) should be passed to the relevant (interactive) native element of the component. (See Root Attribute Forwarding documentation)
    • we use the useRootAttrs composable
  4. ๐Ÿ“œ All boolean properties default to false (falsy)
  5. ๐Ÿ“œ We prevent complex conditions due to big union modelValue types.
  6. ๐Ÿ“œ We provide translations for standard texts inside components, e.g. "OK", "Cancel" etc. and allow to override them.
    • Community contributions to our translations are most welcome!
  7. ๐Ÿ“œ We support common navigation patterns, e.g. keyboard shortcuts
  8. ๐Ÿ“œ We strife to keep the parity between Figma and the implementation as high as possible.
    • We use a shared domain language between UX and DEV.
  9. ๐Ÿ“œ All components can be used standalone in a project without affecting styles of the whole application (so they can be used together with other component libraries). Therefore, we provide two CSS files:
    • Component styles: Required. Defines the styles of the components, no side effects on globals.
    • Global styles: Optional. Applies global styles to the whole application (e.g. color / background color on body, <a> etc.)

Copy link to headline:Naming conventions

  1. ๐Ÿ“œ All (public) components are prefixed with Onyx, e.g. OnyxButton
  2. ๐Ÿ“œ We use v-model(opens in a new tab) for two-way-data-binding wherever possible
  3. ๐Ÿ“œ Component variants are named after what they are, not where they are used (e.g. a link variant "fullWidth" instead of "sideBar")
  4. ๐Ÿ“œ All CSS class names are prefixed with onyx-
  5. ๐Ÿ“œ All CSS variables are prefixed with --onyx-

Copy link to headline:Component Implementation

  1. ๐Ÿ“œ We don't clone DOM nodes. Instead, we can place slots in different places depending on the breakpoint
  2. ๐Ÿ“œ We only use as much JavaScript as necessary (e.g. prefer CSS solutions over JavaScript)
  3. ๐Ÿ“œ Property types are declared and exported as standalone type and referenced in the defineProps
    • the property type can still be declared (and exported) inside the component file to which it belongs
  4. ๐Ÿ“œ We always use the notation props.foo instead of accessing foo directly in the <template> section
  5. ๐Ÿ“œ We structure the component code in the following manner:
    1. types
    2. props
    3. emits
    4. slots
    5. ... everything else grouped by responsibility
    6. defineExpose

Copy link to headline:A11y (Accessibility)

  1. ๐Ÿ“œ We use semantic HTML(opens in a new tab)
  2. ๐Ÿ“œ We keep the DOM tree as flat as possible
  3. ๐Ÿ“œ We follow A11y best practices(opens in a new tab) (level AA)
  4. ๐Ÿ“œ We define aria relevant properties as required
    • e.g. the alt property of the OnyxImage component is required

Copy link to headline:Typescript

  1. ๐Ÿ“œ We use types instead of interfaces
  2. ๐Ÿ“œ We don't use typescript enums(opens in a new tab)
  3. ๐Ÿ“œ We use strict undefined/null checks when implementing the onyx ecosystem

Copy link to headline:CSS

  1. ๐Ÿ“œ Instead of using scoped/module for <style>, we rely on meaningful class structures
    • we use BEM(opens in a new tab) to provide semantic and structured class names
    • all styles related to a component are bundled inside one component class, e.g. the component OnyxInput has one class onyx-input which groups all styles of that component
  2. ๐Ÿ“œ We don't use !important
  3. ๐Ÿ“œ We define only as little style as needed
    • Instead of copying Figma styles, we evaluate what is needed
  4. ๐Ÿ“œ Component styles are limited to the component internals
    • We don't set opinionated margins on the components that define how they are spaced in the page layout.
  5. ๐Ÿ“œ We avoid writing styles on a parent component that are applied to children that are placed in a slot
    • Exception: When the alternative would over-complicate the interface, e.g. by requiring extra properties
  6. ๐Ÿ“œ We prefer styles that don't rely on :not()
  7. ๐Ÿ“œ We use rem(opens in a new tab) for everything. This includes borders, font-sizes etc.

Copy link to headline:Testing

  1. ๐Ÿ“œ Each (public) component is covered by at least 1 screenshot test (via Playwright)
  2. ๐Ÿ“œ All defined component behavior is covered by a playwright test (.ct.tsx file)
  3. ๐Ÿ“œ Utils and composables are covered by Vitest tests (.spec.ts file)
  4. ๐Ÿ“œ We structure our tests by using the arrange-act-assert pattern(opens in a new tab):br