> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# OverflowingList

> Fit a row of items into the available space and show the complete list in a popup.

export const StoryEmbed = ({storyId, title, height = 120}) => <>
    <Tabs>
      <Tab title="Light">
        <iframe title={`${title} (light)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:light`} width="100%" height={height} loading="lazy" allow="clipboard-write" style={{
  border: 0
}} />
      </Tab>
      <Tab title="Dark">
        <iframe title={`${title} (dark)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:dark`} width="100%" height={height} loading="lazy" allow="clipboard-write" style={{
  border: 0
}} />
      </Tab>
    </Tabs>
    <a href={`https://storybook.twenty.com/?path=/story/${storyId}`}>
      Open in Storybook
    </a>
  </>;

`OverflowingList` measures its available width, keeps fitting items in a compact row, and offers a `+N` button that opens the complete list in a popup. The count updates when the container, item content or ordered list changes. Empty lists and lists that fit have no overflow button or exposed popup.

<StoryEmbed storyId="ui-components-overflowinglist--display" title="Overflowing list example" height={280} />

Supply the complete ordered list as keyed elements. Your application owns each item's content, actions and data. The compact row remains visible when the popup opens. The popup repeats the complete list, including the items that fit in the row.

## Usage

```tsx theme={null}
import { OverflowingList, Section } from 'twenty-ui/components/layout';
import { Tag } from 'twenty-ui/primitives/data-display';

const TAGS = ['Customer', 'Partner', 'Priority', 'Renewal'];

export const CompanyTags = () => (
  <Section.Root>
    <Section.Header
      title="Company tags"
      description="Open the count to see all tags."
    />
    <OverflowingList
      style={{ width: 180 }}
      showOverflowCount
      overflowLabel="Show all company tags"
    >
      {TAGS.map((label) => (
        <Tag
          key={label}
          color="blue"
          truncate={false}
          style={{ width: 80, minWidth: 'fit-content' }}
        >
          {label}
        </Tag>
      ))}
    </OverflowingList>
  </Section.Root>
);
```

## Count visibility

| `showOverflowCount` | Behavior when items overflow |
| - | - |
| Omitted | Shows the count on pointer hover, keyboard focus or while the popup is open. |
| `true` | Keeps the count visible. |
| `false` | Hides the count and clips the row. An open popup stays open until dismissed. |

The default mode keeps the current count visibility while an inline item is focused, so showing the count does not push that item out of the row. Focusing the count button makes the count visible.

Use `false` when the surrounding interface provides another way to access the hidden items. Changing it to `false` hides the count without dismissing an already-open popup. `open` and `defaultOpen` can still expose the complete list when items overflow. Removing the overflow items or widening the list until everything fits closes the popup and removes the count button. The count always describes the items outside the compact row.

`maxInlineCount` caps the number of visible row items. Available width can reduce that number further. The popup still contains the complete list. It does not fetch missing items or virtualize the popup.

## Popup state

The list owns its popup state when `open` is omitted. Use `defaultOpen` for its initial state. The default is `false`; an initially open popup still requires overflowing items.

Pass `open` and update it in `onOpenChange` to own the popup state. The callback receives the requested boolean and the installed [Popover](/ui/primitives/surfaces/popover) event details, including `reason`, `event`, `trigger`, `cancel()` and `preventUnmountOnClose()`. Calling `cancel()` prevents the requested state change. In controlled use, update your state only for changes you accept.

Pass `actionsRef` to receive the Popover `close()` and `unmount()` methods. `close()` requests closure through `onOpenChange` and respects cancellation. If your callback calls `preventUnmountOnClose()` to run a caller-owned exit, call `actionsRef.current?.unmount()` when that exit finishes. This releases the retained popup without removing the list and allows it to open again.

```tsx theme={null}
import { useState } from 'react';
import { OverflowingList } from 'twenty-ui/components/layout';
import { Tag } from 'twenty-ui/primitives/data-display';
import { Button } from 'twenty-ui/primitives/input';

const TEAMS = ['Design', 'Engineering', 'Support', 'Operations'];

export const ControlledTeamList = () => {
  const [open, setOpen] = useState(false);

  return (
    <OverflowingList
      open={open}
      onOpenChange={setOpen}
      showOverflowCount
      overflowLabel="Show all teams"
      style={{ width: 220 }}
      triggerProps={{ render: <Button variant="outline" size="sm" /> }}
    >
      {TEAMS.map((team) => (
        <Tag key={team} color="blue">
          {team}
        </Tag>
      ))}
    </OverflowingList>
  );
};
```

<StoryEmbed storyId="ui-components-overflowinglist--controlled" title="Controlled state with a custom trigger" height={280} />

## Native targets and composition

Native `div` attributes, handlers, styles, class names and refs on `OverflowingList` target the compact row root. Use `triggerProps` for the count button and `popupProps` for the popup content div. Both retain their Popover part's native props, handlers, ref and element/function `render` composition.

Customize the trigger with `triggerProps.render`, as in the controlled example, or supply `triggerProps.children` to replace `+N`. Custom components must [forward the supplied props and ref](/ui/primitives/overview#custom-components). Custom popup components must also render the supplied children; OverflowingList owns the item content. `overflowLabel` defaults to "Show all items". The default button's accessible name combines its count and that label, for example "+3 Show all teams". Override `triggerProps['aria-label']` or `popupProps['aria-label']` when their content needs a different name.

`OverflowingList` stops `click`, `mousedown`, `pointerdown`, `keydown` and `keyup` propagation on the trigger and popup by default. This keeps opening the popup and interacting with its items from activating a surrounding field or picker. A handler supplied through `triggerProps` or `popupProps` replaces the default for that event. Call `event.stopPropagation()` in your handler to retain blocking, or omit it to allow that event to bubble. Other events keep their defaults. Handlers on a custom `render` element compose with the supplied props as usual.

When a popup click override allows bubbling, the installed Base UI portal can dispatch that click to a surrounding React ancestor twice with the same native event. This also occurs with a plain `Popover`. OverflowingList preserves that upstream behavior; it does not guarantee one ancestor callback per native popup event when bubbling is enabled.

## Keyboard and focus

Enter, Space and pointer activation open a non-modal popup. Escape and outside interaction dismiss it. Ordinary dismissal restores focus to the count button. Focus already on a visible inline item or an outside control is preserved. The popup supports content, links and buttons with their native keyboard behavior; it does not turn them into menu items or add menu arrow navigation.

Use `popupProps.initialFocus` and `popupProps.finalFocus` to customize opening and dismissal focus through the installed Popover contract.

Each list owns its responsive measurements independently. Unmounting one list releases its observers and leaves other lists working.

## Server rendering and hydration

Server markup includes the first `maxInlineCount` items, or all items when the cap is omitted. Width measurement and popup content become available after client mounting.

Hydration reuses the provisional row and applies responsive measurement after client mounting. Row and popup children are separate rendered instances. Keep state shared between those locations in the caller.

## Migration

The popup continues to show the complete list and uses "Show all items" by default. `showOverflowCount={false}` preserves the clipped row and hides the count. It does not dismiss an already-open popup. The trigger and popup retain their default blocking for click, mousedown, pointerdown, keydown and keyup. Override an individual handler through `triggerProps` or `popupProps` when the surrounding interface should receive that event.

## Props

<ParamField body="actionsRef" type="RefObject<PopoverRootActions | null>">
  Ref exposing the Popover close() and unmount() methods. After preventUnmountOnClose(), call unmount() when the caller-owned exit finishes.
</ParamField>

<ParamField body="children" type="ReactElement<unknown, string | JSXElementConstructor<any>>[]" required>
  Complete ordered list of elements, each with a stable key. The popup contains the complete list, including items visible in the compact row.
</ParamField>

<ParamField body="defaultOpen" type="boolean" default="false">
  Initial popup visibility when uncontrolled. Defaults to false.
</ParamField>

<ParamField body="maxInlineCount" type="number">
  Maximum number of items visible in the compact row. Available width can reduce this count further. The popup still contains the complete list.
</ParamField>

<ParamField body="onOpenChange" type="((open: boolean, eventDetails: PopoverRootChangeEventDetails) => void)">
  Receives the requested open state and unchanged Base UI event details, including reason, event, trigger, cancel() and preventUnmountOnClose().
</ParamField>

<ParamField body="open" type="boolean">
  Controlled popup visibility. A popup can appear only when items overflow.
</ParamField>

<ParamField body="overflowLabel" type="string" default="Show all items">
  Accessible label for the popup. The default overflow button is named by its visible count followed by this label. Defaults to Show all items.
</ParamField>

<ParamField body="popupProps" type="Omit<PopoverPopupProps, &#x22;children&#x22;>">
  Popover.Popup native props, handlers, ref, render composition and focus options for the overflow content. Click, mousedown, pointerdown, keydown and keyup stop propagation by default. Each supplied event handler replaces its default.
</ParamField>

<ParamField body="ref" type="Ref<HTMLDivElement>">
  Ref forwarded to the compact row root div.
</ParamField>

<ParamField body="showOverflowCount" type="boolean">
  Shows the count on hover, keyboard focus or while open by default. Use true to keep it visible whenever items overflow, or false to hide the count and clip the row. An already-open popup stays open until dismissed. Empty lists and lists that fit have no trigger.
</ParamField>

<ParamField
  body="triggerProps"
  type="Omit<
ComponentPropsWithRef<typeof Popover.Trigger>,
'handle' | 'payload' | 'ref'
> & { ref?: Ref<HTMLElement> }"
>
  Popover.Trigger native props, handlers, ref, children and render composition for the count button. Click, mousedown, pointerdown, keydown and keyup stop propagation by default. Each supplied event handler replaces its default. Custom components must forward supplied props and ref.
</ParamField>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.