Base components serve as the basic building blocks of your UIs. They are simple components with little to no dependencies, and many dependents.
Run the following to create a basic UI component:
Make your component's API available to other components by exporting it from the component's main file. Make sure to include the relevant type aliases and interfaces.
For example:
// index.ts export { Button } from './button'; export type { ButtonProps } from './button';
Base components need to be themeable to maintain consistency in style, across compositions.
Style your component using JS variables or CSS custom props that correspond to your theme schema. Provide each prop with a fallback value.
For example:
const Button = ({ children }) => { const style: React.CSSProperties = { backgroundColor: 'var(--primary-color-background, #568cb0)', padding: 'var(--button-padding-medium, 25)', fontWeight: 'var(--button-font-weight, 1rem)', }; return <button style={style}>{children}</button>; };
A customizable component is component that is more likely to be used in new compositions. It allows its consumers to make adjustments via its API, which obviates the need for changes in the component implementation (changes that might force the consumer to create a new component).
Your component should be able to accept style overrides.
To achieve that, have an optional className
prop included in its API. The className
prop should always be placed last in the classnames list.
import { ReactNode } from 'react'; import cx from 'classnames'; import styles from './button.module.scss'; export type ButtonProps = { children?: ReactNode; className?: string; }; export function Button({ children, className }: ButtonProps) { return <button className={cx(styles.button, className)}>{children}</button>; }
Include a ...rest
(spread) prop in your component's API to make it extendable by additional attributes.
Avoid type errors by extending your props type alias/interface with the attributes of the target HTML element.
For example:
import React, { ReactNode } from 'react'; import cx from 'classnames'; import styles from './button.module.scss'; export type ButtonProps = { children?: ReactNode; } & React.HTMLAttributes<HTMLButtonElement>; export function Button({ children, ...rest }: ButtonProps) { return ( <button {...rest} className={className}> {children} </button> ); }
In the following example the 'Button' component is extended with an onClick
event handler
(although such prop has not been explicitly included in that component's API):
import { Button } from '@my-org/design.buttons.button'; const ButtonWithOnClick = () => { return <Button onClick={() => console.log('clicked!')}>Click me!</Button>; };