FezVrasta/popper.js

View on GitHub
website/pages/docs/Composite.mdx

Summary

Maintainability
Test Coverage
<PageCard>

# Composite

Creates a single tab stop whose items are navigated by arrow
keys, which provides list navigation outside of floating element
contexts.

```js
import {Composite, CompositeItem} from '@floating-ui/react';
```

This is useful to enable navigation of a list of items that
aren't part of a floating element. A menubar is an example of a
composite, with each reference element being an item.

<ShowFor packages={['react-dom']}>

<PackageLimited>@floating-ui/react only</PackageLimited>

</ShowFor>

</PageCard>

## Usage

```js
<Composite>
  <CompositeItem>Item 1</CompositeItem>
  <CompositeItem>Item 2</CompositeItem>
  <CompositeItem>Item 3</CompositeItem>
</Composite>
```

The `render{:.keyword}` prop can be used to customize the
rendering of the composite components. Both `Composite{:.class}`
and `CompositeItem{:.class}` accept a JSX element:

```js
<CompositeItem render={<select />}>
  <option />
  <option />
</CompositeItem>
```

<Notice type="error" title="Important">
  When rendering custom components, they must be **open for
  extension**. This means they must [forward the ref to the
  underlying DOM
  node](https://react.dev/reference/react/forwardRef), and they
  must spread all props passed into the component onto the node.
</Notice>

Or a function that returns an element to customize how the HTML
props are spread/passed:

```js
<CompositeItem
  render={(htmlProps) => (
    <select {...htmlProps}>
      <option />
      <option />
    </select>
  )}
/>
```

## Props

```js
interface CompositeProps {
  render?: RenderProp;
  orientation?: 'horizontal' | 'vertical' | 'both';
  loop?: boolean;
  cols?: number;
  disabledIndices?: number[];
  activeIndex?: number;
  onNavigate?(index: number): void;
  itemSizes?: Dimensions[];
  dense?: boolean;
}
```

### `render{:.keyword}`

default: `<div />{:js}`

Determines the element to render.

```js
<Composite render={<button />} />
```

### `orientation{:.keyword}`

default: `'both'{:js}`

Determines the orientation of the composite.

```js
<Composite orientation="horizontal" />
```

### `loop{:.keyword}`

default: `true{:js}`

Determines whether the composite should loop around when
navigating past the first or last item.

```js
<Composite loop={false} />
```

### `cols{:.keyword}`

default: `1{:js}`

Determines the number of columns there are in the composite (i.e.
it's a grid).

```js
<Composite cols={3} />
```

### `disabledIndices{:.keyword}`

Determines which items are disabled. The `disabled{:.keyword}` or
`aria-disabled{:.keyword}` attributes are used by default.

```js
<Composite disabledIndices={[1]} />
```

### `activeIndex{:.keyword}`

default: `undefined{:js}`

Determines which item is active. Used to externally control the
active item.

```js
const [activeIndex, setActiveIndex] = useState(0);
return <Composite activeIndex={activeIndex} />;
```

### `onNavigate{:.keyword}`

default: `undefined{:js}`

Called when the user navigates to a new item. Used to externally
control the active item.

```js
const [activeIndex, setActiveIndex] = useState(0);
return <Composite onNavigate={setActiveIndex} />;
```

### `itemSizes{:.keyword}`

default: `undefined{:js}`

Only for grid navigation, an array of `Dimensions` objects, which
specify the width (number of columns) and height (number of rows)
of each item, so the navigation algorithm can take the variable
sizes into account. If not specified, every item will be treated
as if it has a size of 1 row and 1 column.

```js
<Composite
  itemSizes={[
    {width: 2, height: 2},
    {width: 1, height: 3},
  ]}
/>
```

### `dense{:.keyword}`

default: `false{:js}`

Only for grid navigation, determines if the grid positioning
algorithm should follow CSS Grid's `auto-flow` `dense` algorithm.

```js
<Composite dense />
```