---
name: ActionBar
menu: Components
---

import ActionBar from './ActionBar'
import PropsTable from 'website-src/components/PropsTable'

# ActionBar

The ActionBar contains buttons that allow the user to "act" on the website or the individual page they are on. Depending on the screen size it will appear on the left or bottom of the screen; at medium sizes and smaller, the MenuBar will also appear as the first icon on the ActionBar.

## Basic Usage

Most commonly the ActionBar should be used as a direct child of the Layout component. ActionBar items can be added as direct children of the ActionBar, although the ActionProvider component can provide greater flexibility. (ActionProvider, like ScreenSizeProvider, is automatically included when using the Layout component.)

```jsx
import React from 'react'
import { ActionsGear, ActionsPrint } from '@repay/cactus-icons'
import { ActionBar, Layout } from '@repay/cactus-web'

const MySite = () => (
  <Layout>
    <ActionBar>
      <ActionBar.Item
        id="ab-print"
        icon={<ActionsPrint />}
        onClick={printThisPage}
        aria-label="Print this page"
      />
      <ActionBar.Panel id="ab-settings" icon={<ActionsGear />} aria-label="Settings">
        <h3>I am a settings panel</h3>
        <input name="enable_the_awesome" type="checkbox" />
      </ActionBar.Panel>
    </ActionBar>
    <Layout.Content>
      <h1>Latin Or Something</h1>
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
    </Layout.Content>
  </Layout>
)
```

### ActionBar.Item and ActionBar.Panel

There are two types of items that typically go on the ActionBar: a simple button, ActionBar.Item, and a button that opens a dialog popup, ActionBar.Panel. ActionBar.Item will typically effect change through an `onClick` handler, while the contents of the dialog popup can be just about anything.

Panel dialog popups are opened and closed by clicking the button; they can also be closed by pressing Escape while focus is on the button or within the dialog, or by shifting focus to any element outside the dialog. If you want additional control over the behavior of the dialog, you can use a render prop instead of a component tree:

```jsx
<ActionBar.Panel icon={<ActionsGear />} aria-label="Settings">
  {(toggle, expanded) => (
    <>
      <h3>I am a settings panel</h3>
      <input name="enable_the_awesome" type="checkbox" />
      <button onClick={() => toggle(false)}>Close</button>
    </>
  )}
</ActionBar.Panel>
```

By default, the dialog popup is positioned right next to the ActionBar. The width and padding can be changed via styled-system props, but you can also change the positioning by passing a `positionPopup` callback. This will be called every time the popup becomes visible, with two arguments: the popup div, and the control button.

### Page-specific Actions

Some actions (like a search filter panel) may only apply to some pages, not the entire website. To add an action to the ActionBar without needing to place the ActionBar at the "bottom" of the component tree, an ActionBar.Item can be rendered in any descendant of an ActionProvider and it will appear in the ActionBar rather than inline. The item will be added to the ActionBar when the ActionBar.Item is mounted, and removed when it is unmounted.

```jsx
import React from 'react'
import { ActionsKey } from '@repay/cactus-icons'
import { ActionBar } from '@repay/cactus-web'

//MyPage.tsx
const MyPage = () => (
  <>
    <ActionBar.Item
      id="page-action"
      aria-label="do something on this page"
      icon={<ActionsKey />}
      orderHint="high"
      onClick={doSomethingPageSpecific}
    />
    <PageContent />
  </>
)

// App.tsx
import React from 'react'
import { ActionBar, Layout } from '@repay/cactus-web'
import MyPage from './Mypage'

const App = () =>(
  <Layout>
    // Other layout components
    <ActionBar>
      //Global action bar options
    </ActionBar>
    <Layout.Content>
      <MyPage />
    <Layout.Content>
  </Layout>
)

```

- You must provide an _id_ prop to uniquely identify the action on the ActionBar; if it is not present, an error will be thrown. (We would use _key_ as well, but React doesn't forward it with the props.)
- The _orderHint_ indicates where, relative to other ActionBar items, the item should appear.
  - Possible values are 'top', 'high', 'center' (default), 'low', and 'bottom'.
  - Items with the same hint are rendered in the order they're added, according to how React renders the entire document tree.
- If this technique is used but there is no ActionProvider to capture the item and move it to the ActionBar, the item will instead render inline. (This is how an ActionBar having direct children can be used with no ActionProvider.)
- Works with ActionBar.Panel as well.

### useAction Hook

`useAction` is the low-level hook that allows `ActionBar.Item` to be rendered anywhere.

```js
function useAction(
  element: ReactElement,
  orderHint?: OrderHint,
  key?: string,
): ReactElement | null;
```

You pass in an _element_ that you want added to the ActionBar. Optionally you can give it an _orderHint_. The _key_ is marked as optional because it defaults to the `element.key`, but just as in `ActionBar.Item`, if no key is given an error will be thrown.

The return value depends on whether or not the hook is used within an ActionProvider or not. If an ActionProvider captured the element for use on the ActionBar, the hook returns null. If there is no ActionProvider, the passed-in element is returned unchanged and the dev can decide what (if anything) to do with it.

```jsx
import React from 'react'
import { ActionsKey } from '@repay/cactus-icons'
import { Layout, useAction } from '@repay/cactus-web'

const MyPage = () => {
  const pageAction = (
    <ActionBar.Button key="page-action" onClick={doSomethingPageSpecific}>
      <ActionsKey />
    </ActionBar.Button>
  )
  const renderButton = useAction(pageAction, 'high')
  return (
    <>
      (renderButton && <AlternativeDoSomethingImplementation />)
      <PageContent />
    </>
  )
}
```

> **Note:** Because the child element may be moved and not rendered immediately, any `useEffect` hooks in the same component or ancestor components will run before the DOM has been updated for the action element. The `usePopup` hook, for example, will not work unless it is used "below" the component where `useAction` is called.

### Accessibility

Because ActionBar items typically only have an icon and no text, it may not be obvious to users what it does. This can be circumvented to an extent using ARIA attributes, tooltips, etc., but touch-only users may have no choice but to click the button to see what it does. As such, you should avoid "destructive" side effects such as navigation or directly changing a page in ways that are difficult to undo or not obvious; more often clicking an ActionBar item would toggle a menu or page section that has a more verbose explanation as to its purpose.

## Properties

`ActionBar` takes no custom props, just standard `div` attributes.

### ActionBar.Item

<PropsTable of={ActionBar} staticProp="ActionBarItem" />

### ActionBar.Panel

Any ARIA attributes will be forwarded to the button, except for "aria-haspopup", "aria-controls", and "aria-expanded", which will be overwritten according to the current state of the popup. Non-ARIA props such as event handlers will be set on the wrapper, so they will receive bubbled events from both the button and the contents of the panel.

<PropsTable of={ActionBar} staticProp="ActionBarPanel" />

### Button, PanelWrapper, PanelPopup

These are just styled components for building custom ActionBar functionality with the same look and feel as `ActionBar.Item` and `ActionBar.Panel`.

- **ActionBar.Button**: a styled button
- **ActionBar.PanelWrapper**: a styled div designed to contain a button and a panel popup
- **ActionBar.PanelPopup**: a styled div designed to be hidden or shown as the button is clicked; it also accepts the [padding (but not margin)](https://styled-system.com/api#space) and [layout](https://styled-system.com/api#layout) props from styled-system
