View

Import
import { View } from "reshaped";
import type { ViewProps, ViewItemProps } from "reshaped";
Storybook

Provides flexbox shortcuts while also correctly handling their edge cases

Lets you work with the theme design tokens without writing custom CSS

Supports any custom gap and padding values
Supports 12-column vertical grid layout
Supports rendering as custom HTML tags

Supports changing property values responsively based on the viewport size

Items can be detached for better control over the children layout

Automatically integrates with Hidden utility


View is the most used layout utility in Reshaped as it provides the most common functionality required for building layouts. It can be used to apply common styles based on the design tokens provided by Reshaped and handles a lot of layout edge cases that you would have to solve yourself when using flexbox directly.

View gives you access to multiple flex-based properties, like direction, gap, align for align-items, justify for justyfy-content and wrap. When either of these properties is applied, View automatically turns on flexbox mode and starts behaving like one.

Using these properties should help you compose groups of elements together, as well as build full page layouts. Note, that gap property supports any number value you pass to it and will apply a multiplier of an x1 unit token, which is 4px by default. For example, here gap is 8px:

<View align="center" gap={2} direction="row">
  <Avatar initials="RS" size={12} />
  <Text variant="body-2-1">Reshaped</Text>
</View>

In addition to flexbox API, you can control the View dimensions using properties, like padding, width, height, maxWidth and maxHeight. Same as before, all of them support number values to be treated as multipliers for the x1 unit token. width, height, maxWidth and maxHeight also support literal string values, so you can define px, %, vh and other types of values.

<View
  padding={8}
  width="50%"
  backgroundColor="elevation-base"
  borderColor="neutral-faded"
>
  <View backgroundColor="neutral" height={10} />
</View>

Padding can also be applied individually for every side with paddingTop, paddingBottom, paddingStart and paddingEnd properties or with paddingInline, paddingBlock for horizontal and vertical sides. Individual padding values have more priority than padding property when used together.

<View paddingTop={4} borderColor="neutral">
  <View backgroundColor="neutral-faded" height={10} />
</View>

When used with text content inside of other components inside, you can control its alignment using textAlign property.

<View textAlign="center" width="50%">
  It's a fez. I wear a fez now. Fezes are cool. You know how I sometimes have
  really brilliant ideas? I hate yogurt. It's just stuff with bits in.
</View>

When using View on mobile devices or inside other containers, you might want to make it full-width without making the markup more complex. Using bleed property should help with this case.

Let's look at the following example, where you have multiple paragraphs of text with a View in between them. In order to keep a single wrapper for the text, we would rather apply negative margin to the View with the bleed property.

Same as gap, bleed supports any number value and works as a multiplier of an x1 unit token. Using bleed will automatically remove side borders and border-radius from the View if any were applied.

<View gap={4}>
  <Text as="p">
    Where'd you get the coconuts? Be quiet! Who's that then? The swallow may fly
    south with the sun, and the house martin or the plover may seek warmer
    climes in winter, yet these are not strangers to our land.
  </Text>
  <View bleed={4}>
    <View backgroundColor="neutral-faded" height={10} />
  </View>
  <Text as="p">
    Oh, ow! It's only a model. We shall say 'Ni' again to you, if you do not
    appease us. The swallow may fly south with the sun, and the house martin or
    the plover may seek warmer climes in winter, yet these are not strangers to
    our land.
  </Text>
</View>

aspectRatio property changes the ratio of the the View and its contents. It supports any float value; however, it's easier to pass as a division of numbers, like 4 / 3. You can use it alongside other layout properties defining the size.

<View
  backgroundColor="neutral-faded"
  aspectRatio={16 / 9}
  width="200px"
  borderRadius="medium"
/>

View provides support for positioning elements on the page, providing position, zIndex and inset properties.

For the positions, it supports relative, absolute, fixed, sticky and static. Together with a position value, you can start using inset property to assign its distance from each side of the parent as a base token multiplier. Or you can assign those values individually, with insetTop, insetBottom, insetStart and insetEnd properties.

<View
  position="relative"
  backgroundColor="neutral-faded"
  height="100px"
  borderRadius="medium"
>
  <View position="absolute" insetTop={2} insetEnd={2}>
    <Button icon={IconHeart} />
  </View>
</View>

You can then assign a zIndex value if you need to combine multiple elements positioned next to each other.

When rendering lists, one of the common use cases is to divide them with lines, so View provides you with the divided property out of the box. It automatically respects the direction of the View and works as expected with hidden items.

<View
  divided
  gap={4}
  padding={4}
  direction="row"
  backgroundColor="base"
  borderColor="neutral-faded"
>
  <View width="40px" height="40px" backgroundColor="neutral-faded" />
  <View width="40px" height="40px" backgroundColor="neutral-faded" />
  <View width="40px" height="40px" backgroundColor="neutral-faded" />
</View>

View applies flexbox rules directly to its children and doesn't add any additional markup to the component you provide. However, you can still use View.Item compound component directly in case you need to get access to additional properties.

Same as in flexbox API, you can make your View child take all remaining space, using grow property. That will automatically remove flexbox wrapping from the View and will handle shinking of the other children correctly, when text content inside them goes multiline.

<View direction="row" gap={3}>
  <View
    width="80px"
    height="80px"
    borderRadius="medium"
    backgroundColor="base"
    borderColor="neutral-faded"
  />
  <View.Item grow>
    I am the Doctor, and you are the Daleks! It's a fez. I wear a fez now. Fezes
    are cool. You know when grown-ups tell you 'everything's going to be fine'
    and you think they're probably lying to make you feel better?
  </View.Item>
</View>

In cases when you want to grow an item but also need to apply additional View styles to it – you can apply grow to the View component directly.

<View direction="row" gap={3}>
  <View {...} />
  <View grow backgroundColor="neutral-faded" />
</View>

Unlike in flexbox API, View lets you override gap on the View.Item level. It means that when you use gapBefore property on View.Item, gap value before this item will be updated and you won't need multiple View wrappers to achieve custom spacing in between the View children.

<View gap={4}>
  <Text variant="title-3">Doctor Who</Text>
  <View.Item gapBefore={0}>
    <Text variant="body-1" color="neutral-faded">
      BBC Series
    </Text>
  </View.Item>
  <Text>
    I'm nobody's taxi service; I'm not gonna be there to catch you every time
    you feel like jumping out of a spaceship. I'm the Doctor, I'm worse than
    everyone's aunt. *catches himself* And that is not how I'm introducing
    myself.
  </Text>
</View>

When building complex layout, order property should let you change the rendering order of the children. This could be very helpful when building responsive layouts.

Note, that order works like adding a weight to an item. The bigger the value is, the less priority it will have during rendering. In the following example, we're setting second item order to 1 which moves it to the end of the list:

<View gap={4} direction="row">
  <View.Item>Item 1</View.Item>
  <View.Item order={1}>Item 2</View.Item>
  <View.Item>Item 3</View.Item>
</View>

View can be used to implement multi-column layouts with maximum of 12 columns. On every View.Item, you can pick the amount of columns this item should take.

You don't need to wrap items into separate rows. Instead they will automatically wrap into the next row once the current row overflows.

<View gap={4} direction="row">
  <View.Item columns={6}>
    <View backgroundColor="neutral-faded" height="40px" />
  </View.Item>
  <View.Item columns={6}>
    <View backgroundColor="neutral-faded" height="40px" />
  </View.Item>
  <View.Item columns={4}>
    <View backgroundColor="neutral-faded" height="40px" />
  </View.Item>
  <View.Item columns={8}>
    <View backgroundColor="neutral-faded" height="40px" />
  </View.Item>
</View>

View works with common styles coming from the design tokens. For example, you can assign backgroundColor and borderColor values to it. Changing backgroundColor automatically changes the text color inside it based on the color contrast ratio.

<View
  width="100px"
  height="100px"
  backgroundColor="primary-faded"
  borderColor="primary-faded"
  justify="center"
  align="center"
>
  View
</View>

Same applies for other tokens and styles, like borderRadius or shadow.

<View
  borderRadius="medium"
  shadow="elevated"
  backgroundColor="elevated"
  borderColor="neutral-faded"
  width="100px"
  height="100px"
  justify="center"
  align="center"
>
  View
</View>

Check the properties table for the full list of available styles and values.

All View layout properties support responsive syntax, which means you can pass an object with values and control its rendering based on the viewport size. We're using mobile-first approach which means that you don't have to define a value for every single viewport. Instead, you only need to define the values at which they change and component will apply them from smallest to largest.

If you pass { s: "column", l: "row" }, View will use the column direction for the small and medium screens. For large and extra-large, it will use the row direction.

<View gap={3} direction={{ s: "column", l: "row" }}>
  <View backgroundColor="neutral-faded" height={10} width={10} />
  <View backgroundColor="neutral-faded" height={10} width={10} />
</View>

Properties supporting responsive values:

  • View: gap, align, justify, direction, wrap, height, width, aspectRatio, maxHeight, maxWidth, padding, bleed, position, inset, insetTop, insetBottom, insetStart, insetEnd, borderRadius
  • View.Item: columns, grow, order, gapBefore

When wrapping View children with the Hidden utility, View will recognise it and remove the additional wrapper element to make flexbox gap work as expected. In the following example, we hide second item starting with the m viewport size and gap is resolved correctly:

<View direction="row" gap={3}>
  <View backgroundColor="neutral-faded" height="40px" width="40px" />
  <Hidden hide={{ s: false, m: true }}>
    <View backgroundColor="neutral-faded" height="40px" width="40px" />
  </Hidden>
  <View backgroundColor="neutral-faded" height="40px" width="40px" />
</View>
  • View can be used in many contexts and, therefore, might require to be rendered using specific HTML tags, like ul or ol for lists of items. It can be achieved by using as property on both View and View.Item.
<View as="ul" gap={2}>
  <View.Item as="li">Item 1</View.Item>
  <View.Item as="li">Item 2</View.Item>
</View>