-
Notifications
You must be signed in to change notification settings - Fork 73
Reference‐Conventions
Most layouts can be accomplished with less code using grid
. Use <Stack />
components for vertical spacing, columns for horizontal spacing. This also maps very nicely to Figma auto-layouts, works in RTL, and doesn't require overrides for start/end elements.
https://mxstbr.com/thoughts/margin/
By nesting stacks, you can accomplish a clean consistent layout with very minimal css!
// 💚
.contentContainer,
header,
main {
display: grid;
}
.contentContainer {
gap: 3.2rem;
}
header {
gap: 0.8rem;
}
main {
gap: 1.6rem;
}
// 💚
<div className="contentContainer">
<header>
<h1>{title}</h1>
<p>{subtitle}</h1>
</header>
<section>
{...firstSection}
<section>
<section>
{...secondSection}
<section>
</div>
It's easy to do dynamic and conditional styles with cx
(classnames) or in some cases, data-attributes.
// example of conditional className
<button
className={cx({ disabled: !!props.disabled }, styles.button)}
/>;
// example of data driven attributes
<div
className={styles.colorChanger}
data-hex={state.hex}
data-variant={props.variant}
/>;
Props and configs might reduce lines of code, but are difficult to refactor and lead to big complex components.
// ❌ bad, configuration via props
<MyPage
showHeader
headerTabs={[...]}
showFooter
showFooterLogo
>
{content}
</MyPage>
// 💚 good, composition of reuseable elements! 👍
<PageContainer>
<Header>
<Tab />
<Tab />
</Header>
<Main>{content}</Main>
<Footer>
<Logo />
</Footer>
</PageContainer>
This helps to prevent name-clashes, demonstrate where a function or value originates, avoids big blocks of code when a component has many props, and requires less refactoring when things are renamed or removed.
// 💚
const MyButton = (props: MyButtonProps) => {
<button onClick={props.onClick}>{props.children}</button>;
};
I.e. props start with on
and handlers functions start with handle
// 💚
const ClickTracker = (props) => {
const handleClick = (e) => {
trackClick(e);
props.onClick(e);
};
return <button onClick={handleClick}>Click Me</button>;
};
Example: easy to assume this is a number, but it's not! Explicit return types prevent confusion.
// 💚
const getQuantity = (): string => {
return state.quantity;
};
// 💚
const MyButton = (props: MyButtonProps): FC<Props> => <button {...props} />;
// 💚
const emitEvent = (params) => {
props.onEvent({ id: params.id, value: params.value });
};
See this article for reasons why 'default is bad'.