Skip to content

Commit

Permalink
docs(components): Document composability best practices [107012] (#2136)
Browse files Browse the repository at this point in the history
* First crack at a composability guide

* 2nd draft with changes based on review

* Fix typos

* Fix capitalization
  • Loading branch information
Aiden-Brine authored Nov 25, 2024
1 parent 0c3eed6 commit d5c6935
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@ import { getGIF, loadingGIF } from "./getGIF";

<Meta title="Guides/Getting started with React" />

# Getting Started with React

## Things to know.
# Getting started with React

## What is React

At its core React is simply a JavaScript view library layer. It provides us with
a way to define and render view components. It also aids with tracking and
re-rendering changes to data that the components are representing.

## What is a Component
## What is a component

Much as a function in programing allows you to encapsulate, test and reuse logic
a React Component allows you to encapsulate, test and reuse pieces of your UI.
Expand Down Expand Up @@ -64,7 +62,7 @@ There are a few things going on in the example above. Lets break them down:
| `{ text, yell }: MessageProps` | There are two parts to this. Starting on the right `MessageProps` indicates that this funciton takes a parameter of type `MessageProps`. On the left the `{ text, yell }` unpacks the parameter into local variables. |
| `return <p>{text}</p>` | Every React component will return an [element](https://reactjs.org/docs/rendering-elements.html) or [fragment](https://reactjs.org/docs/fragments.html). (Note the [fragment short hand syntax](https://reactjs.org/docs/fragments.html#short-syntax).) |

## It's Components All the Way Down
## It's components all the way down

In React everything is a component. A typical page will consist of one top level
component representing the main view. Then within that page you will break down
Expand All @@ -79,7 +77,7 @@ smaller components. Brad Frost covers this break down very well with
When you are writing a front end using React each of the levels he talks about
are represented by components functions.

## Composing Components
## Composing components

As mentioned above a lot of the power of React comes from being able to build
components out of other components. Lets take a look at an example on how to do
Expand All @@ -89,7 +87,7 @@ For this example we are going to build a card that allows you to enter a topic
and then search for a related gif.

<Canvas>
<Story name="Composing Components">
<Story name="Gif Gift">
{() => {
const [topic, setTopic] = useState();
const [url, setURL] = useState();
Expand Down Expand Up @@ -117,7 +115,7 @@ and then search for a related gif.
> `function getGIF(topic: string): Promise<string>;` that will return a promise
> resolving to a url.
### Breaking it Down
### Breaking it down

```tsx
const [topic, setTopic] = useState();
Expand Down Expand Up @@ -183,3 +181,43 @@ The final part of our example defines the custom actions needed to power our
component. In this case the action when the user clicks on the **Search**
button. Here we call the `setURL` setter to show the `loadingGIF`. Then, we call
`setURL` awaiting the async response of `getGIF`.

## Types of components in Atlantis and their ability for customization

#### 1. Primitive components:

Examples: [Icon](..?path=/docs/components-images-and-icons-icon--docs),
[Avatar](..?path=/docs/components-images-and-icons-avatar--docs)

These components do not accept children and have minimal customization.

#### 2. Simple components:

Examples: [Button](..?path=/docs/components-actions-button--docs),
[Link](..?path=/docs/components-text-and-typography-link--docs)

These allow basic customization through props or limited children, like
`ReactNode` or specific child types.

#### 3. Compound components:

Examples: [Chip](..?path=/docs/components-selections-chip--docs),
[DataList](..?path=/docs/components-lists-and-tables-datalist--docs)

These are part of larger compositions and may validate their children types to
maintain internal consistency.

#### 4. Strict complex components:

Example:
[Autocomplete](..?path=/docs/components-forms-and-inputs-autocomplete--docs),

These have multiple UI pieces they are built out of but strict APIs and limited
customization.

#### 5. Customizable complex components:

Example: [Combobox](..?path=/docs/components-selections-combobox--docs)

These also have multiple UI pieces they are built out of but offer options for
customization.
77 changes: 77 additions & 0 deletions docs/guides/customizing-components.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Meta } from "@storybook/addon-docs";

<Meta title="Guides/Customizing components" />

# Customizing components

### Philosophy: easy to use, flexible to customize

Atlantis is designed to make building consistent, accessible, and visually
appealing user interfaces as effortless as possible. Our goal is to create
components that work out of the box, requiring minimal setup or configuration
from consumers.

While we strive to cover the most common design scenarios with thoughtful
defaults, we understand that unique use cases may require customization. For
these scenarios, we provide mechanisms to extend or modify our components in a
way that maintains flexibility without compromising the integrity of the
components.

We recommend using the default implementations wherever possible to benefit from
consistency, maintainability, and built in accessibility. However, if you choose
to customize, please note that the responsibility for ensuring proper
functionality and cohesion will rest with you.

Atlantis aims to strike a balance between simplicity, flexibility, and
consistency.

### Primary customization approach: named render props

In Atlantis, our primary approach to enabling customization is through named
render props, using the `customRender____` pattern. This method allows consumers
to inject their own UI logic while retaining the default behaviors and
functionality of the component.

#### Example: customRenderItem

Here's an example of how to use a named render prop to customize the rendering
of items in a [List](..?path=/docs/components-lists-and-tables-list--docs)
component:

```tsx
const renderProductItem = item => (
<Flex template={["shrink", "grow"]} align="start">
<Text>{item.price}</Text>
<Heading level={4}>{item.name}</Heading>
</Flex>
);

export const CustomRenderExample = () => (
<List items={items} customRenderItem={renderProductItem} />
);
```

In this example, the default List behavior (such as the main list structure and
handling item interactions) is preserved. Only the presentation of individual
items is customized.

### Other customization approaches

While custom render functions are our primary approach it is not used in all
places. For simple cases where customization does not depend on internal state,
we have chosen to extend prop types to allow for a `ReactNode` to be passed in.

#### Example: Tab component (see [Tabs](..?path=/docs/components-navigation-tabs--docs))

Instead of introducing `customRenderLabel`, the `Tab` component was updated to
allow the `label` prop to accept a `ReactNode`.

```tsx
<Tab label={<MyCustomLabel />} />
```

This approach was chosen to provide a simpler experience for those implementing
Atlantis components. Customizing the `label` didn’t require exposing or
interacting with the `Tab`’s internal state (e.g., active state styling). Once
the design becomes more complex a custom render function would become a better
fit.

0 comments on commit d5c6935

Please sign in to comment.