{"id":13672926,"url":"https://github.com/vonovak/react-navigation-header-buttons","last_synced_at":"2025-04-14T08:53:26.963Z","repository":{"id":29242591,"uuid":"119259453","full_name":"vonovak/react-navigation-header-buttons","owner":"vonovak","description":"Easily render header buttons for react-navigation","archived":false,"fork":false,"pushed_at":"2024-03-16T13:18:31.000Z","size":6288,"stargazers_count":843,"open_issues_count":3,"forks_count":59,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-03-20T23:35:34.038Z","etag":null,"topics":["hacktoberfest","react-native","react-navigation"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vonovak.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":["vonovak"]}},"created_at":"2018-01-28T13:12:53.000Z","updated_at":"2024-08-22T08:00:28.645Z","dependencies_parsed_at":"2024-04-14T18:00:12.991Z","dependency_job_id":null,"html_url":"https://github.com/vonovak/react-navigation-header-buttons","commit_stats":{"total_commits":194,"total_committers":24,"mean_commits":8.083333333333334,"dds":0.2680412371134021,"last_synced_commit":"1c7d664fb250ce8827f347983702976d8b4831f0"},"previous_names":[],"tags_count":53,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vonovak%2Freact-navigation-header-buttons","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vonovak%2Freact-navigation-header-buttons/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vonovak%2Freact-navigation-header-buttons/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vonovak%2Freact-navigation-header-buttons/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vonovak","download_url":"https://codeload.github.com/vonovak/react-navigation-header-buttons/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248852107,"owners_count":21171839,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hacktoberfest","react-native","react-navigation"],"created_at":"2024-08-02T09:01:57.878Z","updated_at":"2025-04-14T08:53:26.929Z","avatar_url":"https://github.com/vonovak.png","language":"TypeScript","funding_links":["https://github.com/sponsors/vonovak"],"categories":["TypeScript"],"sub_categories":[],"readme":"# react-navigation-header-buttons\n\nThis package will help you render buttons in the navigation bar and handle the styling, so you don't have to. It mimics the appearance of native navbar buttons and offers a simple but also flexible interface for you to interact with.\n\n✅ DRY library api\n\n✅ Works great with icons from `@expo/vector-icons` / `react-native-vector-icons` or any other icon library\n\n✅ Supports Expo Router, and both [JS](https://reactnavigation.org/docs/stack-navigator) and [native](https://reactnavigation.org/docs/native-stack-navigator/) stack\n\n✅ Beautiful overflow menus for items that don't fit into the navbar\n\n✅ [Recipes](#recipes) and examples included\n\n✅ Written in TS\n\n✅ Test suite included (mostly good only for the maintainer, but hey, not bad to know it's there)\n\n\u003c!--\n#### Library status\n\nMature: the library is stable and feature-complete. It won't be updated often not because it's abandoned, but because it doesn't need to be.\n--\u003e\n\n#### Demo App\n\nContains many examples in the [example folder](https://github.com/vonovak/react-navigation-header-buttons/tree/master/example/src/screens). I highly recommend you check it out to get a better idea of the api.\n\n#### Quick Example\n\n\u003cspan\u003e\n\u003cimg alt=\"demo\" src=\"img/header_buttons.gif\" height=\"668\" /\u003e\n\u003c/span\u003e\n\n\u003cdetails\u003e\u003csummary\u003emore screenshots\u003c/summary\u003e\n\u003cimg alt=\"nativeOverflowMenu\" src=\"img/nativeMenu.png\" height=\"400\" /\u003e\n\n\u003c/details\u003e\n\nThe corresponding code:\n\n```tsx\nimport * as React from 'react';\nimport MaterialIcons from '@expo/vector-icons/MaterialIcons';\nimport {\n  HeaderButtons,\n  Item,\n  HiddenItem,\n  OverflowMenu,\n  Divider,\n  ItemProps,\n  HiddenItemProps,\n  HeaderButtonProps,\n  HeaderButton,\n} from 'react-navigation-header-buttons';\nimport { Text } from 'react-native';\n\nconst MaterialHeaderButton = (props: HeaderButtonProps) =\u003e (\n  // the `props` here come from \u003cItem ... /\u003e\n  // you may access them and pass something else to `HeaderButton` if you like\n  \u003cHeaderButton IconComponent={MaterialIcons} iconSize={23} {...props} /\u003e\n);\n\nconst EditItem = ({ onPress }: Pick\u003cItemProps, 'onPress'\u003e) =\u003e {\n  return \u003cItem title=\"edit\" onPress={onPress} /\u003e;\n};\n\nconst ReusableHiddenItem = ({ onPress }: Pick\u003cHiddenItemProps, 'onPress'\u003e) =\u003e (\n  \u003cHiddenItem title=\"hidden2\" onPress={onPress} disabled /\u003e\n);\n\nexport function UsageWithIcons({ navigation }) {\n  React.useLayoutEffect(() =\u003e {\n    navigation.setOptions({\n      title: 'Demo',\n      headerRight: () =\u003e (\n        \u003cHeaderButtons HeaderButtonComponent={MaterialHeaderButton}\u003e\n          \u003cItem\n            title=\"search\"\n            iconName=\"search\"\n            onPress={() =\u003e alert('search')}\n          /\u003e\n          \u003cEditItem onPress={() =\u003e alert('Edit')} /\u003e\n          \u003cOverflowMenu\n            OverflowIcon={({ color }) =\u003e (\n              \u003cMaterialIcons name=\"more-horiz\" size={23} color={color} /\u003e\n            )}\n          \u003e\n            \u003cHiddenItem title=\"hidden1\" onPress={() =\u003e alert('hidden1')} /\u003e\n            \u003cDivider /\u003e\n            \u003cReusableHiddenItem onPress={() =\u003e alert('hidden2')} /\u003e\n          \u003c/OverflowMenu\u003e\n        \u003c/HeaderButtons\u003e\n      ),\n    });\n  }, [navigation]);\n\n  return \u003cText\u003edemo!\u003c/Text\u003e;\n}\n```\n\n## Installation \u0026 Setup\n\nSee [Installation \u0026 Setup](INSTALL.md)\n\n## Usage\n\n### `HeaderButtons`\n\nIs a wrapper over all the visible header buttons (those can be text-buttons, icon-button, or any custom react elements).\n\nYou should provide the `HeaderButtonComponent` prop that encapsulates how all buttons rendered in children will look. Typically, you'll want to provide a component that wraps [`HeaderButton`](#headerbutton) as seen in the example above. However, you're free to use your own component (see `HeaderButton.tsx` for reference).\n\nIn particular, it allows setting `IconComponent`, `size` and `color` in one place so that you don't need to repeat it for each icon-button - but you can override those for each `Item` if you like.\n\n`HeaderButtons` accepts:\n\n| prop and type                                              | description                                                                                                                                                     | note                                                                                                                                              |\n| ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |\n| HeaderButtonComponent?: `ComponentType\u003cHeaderButtonProps\u003e` | component that renders the buttons, `HeaderButton` by default                                                                                                   | Typically, you'll want to provide a component that wraps `HeaderButton` provided by this package, as seen in the [quick example](#quick-example). |\n| children: ReactNode                                        | whatever you want to render inside                                                                                                                              | Typically, `Item` or your component that renders `Item`, but it can be any React element.                                                         |\n| left?: boolean                                             | whether the `HeaderButtons` are on the left from header title                                                                                                   | false by default, it only influences styling (margins) in a subtle way                                                                            |\n| preset?: 'tabHeader' \\| 'stackHeader'                      | headers are typically rendered in Stack Navigator, however, you can also render them in a Tab Navigator header. Pass 'tabHeader' if button margins are missing. | 'stackHeader' by default                                                                                                                          |\n\n### `Item`\n\nRenders text, or icon inside a [PlatformPressable](https://reactnavigation.org/docs/elements/#platformpressable). Take a look at the example above to see how to use it.\n\n`Item` accepts:\n\n| prop and type           | description                                                                           |\n| ----------------------- | ------------------------------------------------------------------------------------- |\n| title: string           | title for the button, required                                                        |\n| onPress: ?() =\u003e any     | function to call on press                                                             |\n| iconName?: string       | icon name, used together with the `IconComponent` prop                                |\n| style?: ViewStyle       | style to apply to the touchable element that wraps the button                         |\n| buttonStyle?: ViewStyle | style to apply to the text / icon                                                     |\n| other props             | whatever else you want to pass to the underlying `PlatformPressable` (eg. `disabled`) |\n\n`Item` also accepts other props that you'll typically not need to pass because `HeaderButtonComponent` already knows them (eg. `iconSize`) or because they are pulled from the React Navigation's theme object (`color`).\n\n| additional props and type                                | description                                                                             | note |\n| -------------------------------------------------------- | --------------------------------------------------------------------------------------- | ---- |\n| IconComponent?: ComponentType                            | component to use for the icons, for example from `react-native-vector-icons`            |      |\n| iconSize?: number                                        | icon size                                                                               |      |\n| color?: string                                           | color of icons and buttons                                                              |      |\n| renderButton?: (params: VisibleButtonProps) =\u003e ReactNode | renders the body of the button (text or icon), defaults to `defaultRenderVisibleButton` |      |\n\n### `OverflowMenu`\n\nDefines the behavior for overflow button (if there is one). You can render `OverflowMenu` only by itself too, you do not need to wrap it in `HeaderButtons`.\nThe most important prop is `onPress` which defines what kind of overflow menu we should show.\n\nIf `OverflowMenu` contains no valid child elements, nothing will be rendered at all. (No `OverflowIcon`, no wrapper.)\n\nThe package exports common handlers you can use, but you can provide your own too (via the `onPress` prop):\n\n| exported handler                       | description                                                                                                                                                                                                                                                                                                                                                 |\n| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `defaultOnOverflowMenuPress`           | The default. Uses `overflowMenuPressHandlerActionSheet` on iOS, and `overflowMenuPressHandlerDropdownMenu` otherwise.                                                                                                                                                                                                                                       |\n| `overflowMenuPressHandlerActionSheet`  | This is iOS-only: it displays overflow items in an `ActionSheetIOS`                                                                                                                                                                                                                                                                                         |\n| `overflowMenuPressHandlerPopupMenu`    | This is Android-only: it displays overflow items using `UIManager.showPopupMenu`                                                                                                                                                                                                                                                                            |\n| `overflowMenuPressHandlerDropdownMenu` | Can be used on iOS, Android and Web. Displays overflow items in a material popup adapted from [react-native-paper](https://callstack.github.io/react-native-paper/docs/components/Menu), credit for an amazing job goes to them. This `Menu` is bundled in this library (no dependency on `react-native-paper`) but only `require`d if you actually use it. |\n\nYou can also use the [react-native-menu](https://github.com/react-native-menu/menu) to show the overflow menu, as seen in the example app.\n\n`OverflowMenu` accepts:\n\n| prop and type                                | description                                                 | note                                                                                                                    |\n| -------------------------------------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |\n| OverflowIcon: ReactElement \\| ComponentType  | React element or component for the overflow icon            | if you provide a component, it will receive `color` prop as seen in example above                                       |\n| style?: ViewStyle                            | optional styles for overflow button                         | there are some default styles set, as seen in `OverflowButton.tsx`                                                      |\n| onPress?: (OnOverflowMenuPressParams) =\u003e any | function that is called when overflow menu is pressed.      | This will override the default handler. Note the default handler offers (limited) customization. See more in \"Recipes\". |\n| testID?: string                              | testID to locate the overflow button in e2e tests           | the default is available under `import { OVERFLOW_BUTTON_TEST_ID } from 'react-navigation-header-buttons/e2e'`          |\n| accessibilityLabel?: string                  |                                                             | 'More options' by default                                                                                               |\n| left?: boolean                               | whether the `OverflowMenu` is on the left from header title | false by default, it just influences styling. No need to pass this if you already passed it to `HeaderButtons`.         |\n| children: ReactNode                          | the overflow items                                          | typically `HiddenItem`s, please read the note below                                                                     |\n| preset?: 'tabHeader' \\| 'stackHeader'        |                                                             | see [props of headerbuttons](#headerbuttons)                                                                            |\n| other props                                  | props passed to the nested `PlatformPressable`              | pass eg. `pressColor` to control ripple color on Android                                                                |\n\n\u003e [!NOTE]\n\u003e There are important limitations on what can be passed as children to `OverflowMenu`:\n\nChildren passed to `OverflowMenu` should be\n\n- either `HiddenItem`s\n- or plain function components (no class components) without hooks that return `HiddenItem`, as seen in the example above.\n\nAnything else will be ignored and will not appear in the overflow menus shown by `overflowMenuPressHandlerActionSheet` and `overflowMenuPressHandlerPopupMenu`.\nOnly `overflowMenuPressHandlerDropdownMenu` supports rendering custom elements, such as `\u003cDivider /\u003e` (which is exported) or your custom ones.\n\nThis limitation may look weird, but it should not really bother you in any way: if you need to have state in your items, lift the state up.\nThe limitation exists because we need to be able to transform declarative React elements into imperative calls (`ActionSheetIOS.showActionSheetWithOptions` / `UIManager.showPopupMenu`).\nIf this is a problem for you for some reason, please raise an issue, and we'll see what can be done about it.\n\n\u003cdetails\u003e\u003csummary\u003eexamples\u003c/summary\u003e\n\u003cp\u003e\n\nPlease see [`UsageWithOverflowComplex.tsx`](https://github.com/vonovak/react-navigation-header-buttons/blob/master/example/src/screens/UsageWithOverflowComplex.tsx) for valid examples!\n\nThese will NOT work with `overflowMenuPressHandlerActionSheet` and `overflowMenuPressHandlerPopupMenu`:\n\n1. WRONG! no hooks are allowed!\n\n```js\nfunction MyComponent({ title }) {\n  const [titleFromState, setTitle] = React.useState('from state hook');\n  return (\n    \u003cHiddenItem title={titleFromState + title} onPress={() =\u003e alert('fail')} /\u003e\n  );\n}\n\n\u003cOverflowMenu\n  OverflowIcon={\u003cIonicons name=\"ios-more\" size={23} color=\"blue\" /\u003e}\n\u003e\n  \u003cMyComponent /\u003e\n\u003c/OverflowMenu\u003e;\n```\n\n2. WRONG! you can nest `HiddenItem` only once, not twice\n\n```js\nconst HiddenItemWrapped = () =\u003e \u003cHiddenItem title=\"hidden2\" onPress={() =\u003e alert('hidden2')} /\u003e;\nconst HiddenItemWrappedTwice = ()=\u003e \u003cHiddenItemWrapped /\u003e\n\n\u003cOverflowMenu OverflowIcon={\u003cIonicons name=\"ios-more\" size={23} color=\"blue\" /\u003e}\u003e\n  \u003cHiddenItemWrappedTwice /\u003e\n\u003c/OverflowMenu\u003e;\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n#### `HiddenItem`\n\n`HiddenItem` accepts:\n\n| prop and type          | description                                                        | note                                                                   |\n| ---------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------- |\n| title: string          | title for the button, required                                     |                                                                        |\n| style?: ViewStyle      | style to apply to the touchable element that wraps the text        |                                                                        |\n| titleStyle?: TextStyle | style to apply to the text                                         |                                                                        |\n| onPress: ?() =\u003e any    | function to call on press                                          |                                                                        |\n| testID?: string        | testID to locate view in e2e tests                                 |                                                                        |\n| disabled?: boolean     | disabled 'item' is greyed out and `onPress` is not called on touch |                                                                        |\n| destructive?: boolean  | flag specifying whether this item is destructive                   | only applies to items shown with `overflowMenuPressHandlerActionSheet` |\n\n### `HeaderButtonsProvider` / `HeaderButtonsProviderPlain` / `HeaderButtonsProviderDropdownMenu`\n\nYou need to wrap your root component with a HeaderButtons Provider. `stackType` is a required prop, which indicates whether you're using a native or JS stack.\n\nImporting: `import { your_chosen_provider } from 'react-navigation-header-buttons/your_chosen_provider'`.\n\nThere are 3 providers to choose from. Read more in [Installation \u0026 Setup](INSTALL.md).\n\nOptional `spaceAboveMenu` prop can be used to set the distance between the top of the screen and the top of the overflow menu when using `overflowMenuPressHandlerDropdownMenu`.\n\n### `HeaderButton`\n\n`HeaderButton` is where all the `onPress`, `title` and Icon-related props (color, size) meet to render actual button.\n\nYou can fully customize what it renders inside of the `PlatformPressable` using the `renderButton?: (params: VisibleButtonProps) =\u003e ReactNode` prop.\n\n## Recipes\n\n#### Closing the overflow menu from `overflowMenuPressHandlerDropdownMenu` manually\n\n`overflowMenuPressHandlerDropdownMenu` supports rendering custom items in the menu. In your item's onPress handler, you can call `closeMenu` to close the menu manually.\n\n```ts\nconst { closeMenu } = useOverflowMenu();\n```\n\n#### Customizing the overflow menu\n\nThe default handler for overflow menu on iOS is `overflowMenuPressHandlerActionSheet`.\n\nOne of the usual things you may want to do is override the cancel button label on iOS - see [example](example/src/screens/UsageWithOverflow.tsx).\n\nYou can also use the [react-native-menu](https://github.com/react-native-menu/menu) (or similar) to show the overflow menu, as seen in the example app.\n\n#### Using custom text transforms\n\nUse the `buttonStyle` prop to set [`textTransform`](https://reactnative.dev/docs/text-style-props#texttransform) styles for button titles.\n\n#### How to integrate in your project\n\nThis sections covers how you should use the library in your project. Please note that there are numerous [example screens](https://github.com/vonovak/react-navigation-header-buttons/tree/master/example/src/screens).\n\n1 . Define one file where the styling of header buttons is taken care of.\n\n```js\n// MyHeaderButtons.js\n\nimport * as React from 'react';\nimport MaterialIcons from 'react-native-vector-icons/MaterialIcons';\nimport { HeaderButtons, HeaderButton } from 'react-navigation-header-buttons';\n\n// define IconComponent, color, sizes and OverflowIcon in one place\nconst MaterialHeaderButton = (props) =\u003e (\n  \u003cHeaderButton\n    IconComponent={MaterialIcons}\n    iconSize={23}\n    color=\"blue\"\n    {...props}\n  /\u003e\n);\n\nexport const MaterialHeaderButtons = (props) =\u003e {\n  return (\n    \u003cHeaderButtons HeaderButtonComponent={MaterialHeaderButton} {...props} /\u003e\n  );\n};\n```\n\n2 . Import header buttons from the file defined previously.\n\n```js\n// SomeScreen.js\nimport { MaterialHeaderButtons } from './MyHeaderButtons';\nimport { Item } from 'react-navigation-header-buttons';\n\nReact.useLayoutEffect(() =\u003e {\n  navigation.setOptions({\n    title: 'Demo',\n    // use MaterialHeaderButtons with consistent styling across your app\n    headerRight: () =\u003e (\n      \u003cMaterialHeaderButtons\u003e\n        \u003cItem\n          title=\"add\"\n          iconName=\"search\"\n          onPress={() =\u003e console.warn('add')}\n        /\u003e\n        \u003cItem title=\"edit\" onPress={() =\u003e console.warn('edit')} /\u003e\n      \u003c/MaterialHeaderButtons\u003e\n    ),\n  });\n}, [navigation]);\n```\n\n### Theming\n\nColors for Android ripple effect, text and icons come from [React Navigation's theme](https://reactnavigation.org/docs/themes/), so you do not need to work with colors, except in `OverflowIcon`. You can always override colors of text\u0026icons (using `color` prop) or of the ripple effect on Android (using `pressColor` prop) as [documented](#item).\n\n### Known issues / TODOs\n\n- styling support for material dropdown menu is missing\n- item margins should be reviewed; don't hesitate to contribute - [this](https://github.com/infinitered/reactotron/blob/master/docs/plugin-overlay.md) could help\n- RTL is not tested\n- web support is experimental. On the web, you'll probably want to use different interaction patterns anyway.\n- ripple may look different on the header buttons vs on the back button if your version of react navigation does not have [this PR](https://github.com/react-navigation/react-navigation/pull/11386).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvonovak%2Freact-navigation-header-buttons","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvonovak%2Freact-navigation-header-buttons","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvonovak%2Freact-navigation-header-buttons/lists"}