diff --git a/android/src/base/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt b/android/src/base/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt
index 59f43bfc9c..8a3ce459a2 100644
--- a/android/src/base/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt
+++ b/android/src/base/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt
@@ -57,5 +57,6 @@ class KeyboardControllerPackage : BaseReactPackage() {
KeyboardControllerViewManager(reactContext),
KeyboardGestureAreaViewManager(reactContext),
OverKeyboardViewManager(reactContext),
+ KeyboardToolbarExcludeViewManager(reactContext),
)
}
diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardToolbarExcludeViewManagerImpl.kt b/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardToolbarExcludeViewManagerImpl.kt
new file mode 100644
index 0000000000..5a3078db0e
--- /dev/null
+++ b/android/src/main/java/com/reactnativekeyboardcontroller/managers/KeyboardToolbarExcludeViewManagerImpl.kt
@@ -0,0 +1,17 @@
+package com.reactnativekeyboardcontroller.managers
+
+import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.uimanager.ThemedReactContext
+import com.reactnativekeyboardcontroller.views.KeyboardToolbarExcludeReactViewGroup
+
+@Suppress("detekt:UnusedPrivateProperty")
+class KeyboardToolbarExcludeViewManagerImpl(
+ mReactContext: ReactApplicationContext,
+) {
+ fun createViewInstance(reactContext: ThemedReactContext): KeyboardToolbarExcludeReactViewGroup =
+ KeyboardToolbarExcludeReactViewGroup(reactContext)
+
+ companion object {
+ const val NAME = "KeyboardToolbarExcludeView"
+ }
+}
diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigator.kt b/android/src/main/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigator.kt
index 8a0d6ec4ee..975aec8e84 100644
--- a/android/src/main/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigator.kt
+++ b/android/src/main/java/com/reactnativekeyboardcontroller/traversal/ViewHierarchyNavigator.kt
@@ -5,6 +5,7 @@ import android.view.ViewGroup
import android.widget.EditText
import com.facebook.react.bridge.UiThreadUtil
import com.reactnativekeyboardcontroller.extensions.focus
+import com.reactnativekeyboardcontroller.views.KeyboardToolbarExcludeReactViewGroup
object ViewHierarchyNavigator {
fun setFocusTo(
@@ -25,7 +26,7 @@ object ViewHierarchyNavigator {
fun findEditTexts(view: View?) {
if (isValidTextInput(view)) {
editTexts.add(view as EditText)
- } else if (view is ViewGroup) {
+ } else if (view is ViewGroup && view !is KeyboardToolbarExcludeReactViewGroup) {
for (i in 0 until view.childCount) {
findEditTexts(view.getChildAt(i))
}
@@ -91,7 +92,7 @@ object ViewHierarchyNavigator {
if (isValidTextInput(child)) {
result = child as EditText
- } else if (child is ViewGroup) {
+ } else if (child is ViewGroup && child !is KeyboardToolbarExcludeReactViewGroup) {
// If the child is a ViewGroup, check its children recursively
result = findEditTextInHierarchy(child, direction)
}
diff --git a/android/src/main/java/com/reactnativekeyboardcontroller/views/KeyboardToolbarExcludeReactViewGroup.kt b/android/src/main/java/com/reactnativekeyboardcontroller/views/KeyboardToolbarExcludeReactViewGroup.kt
new file mode 100644
index 0000000000..2ef1253f34
--- /dev/null
+++ b/android/src/main/java/com/reactnativekeyboardcontroller/views/KeyboardToolbarExcludeReactViewGroup.kt
@@ -0,0 +1,12 @@
+package com.reactnativekeyboardcontroller.views
+
+import android.annotation.SuppressLint
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.views.view.ReactViewGroup
+
+@SuppressLint("ViewConstructor")
+class KeyboardToolbarExcludeReactViewGroup(
+ reactContext: ThemedReactContext,
+) : ReactViewGroup(reactContext) {
+ // semantic view used in KeyboardToolbar traverse algorithm
+}
diff --git a/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardToolbarExcludeViewManager.kt b/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardToolbarExcludeViewManager.kt
new file mode 100644
index 0000000000..c27b93e93a
--- /dev/null
+++ b/android/src/paper/java/com/reactnativekeyboardcontroller/KeyboardToolbarExcludeViewManager.kt
@@ -0,0 +1,18 @@
+package com.reactnativekeyboardcontroller
+
+import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.views.view.ReactViewManager
+import com.reactnativekeyboardcontroller.managers.KeyboardToolbarExcludeViewManagerImpl
+import com.reactnativekeyboardcontroller.views.KeyboardToolbarExcludeReactViewGroup
+
+class KeyboardToolbarExcludeViewManager(
+ mReactContext: ReactApplicationContext,
+) : ReactViewManager() {
+ private val manager = KeyboardToolbarExcludeViewManagerImpl(mReactContext)
+
+ override fun getName(): String = KeyboardToolbarExcludeViewManagerImpl.NAME
+
+ override fun createViewInstance(reactContext: ThemedReactContext): KeyboardToolbarExcludeReactViewGroup =
+ manager.createViewInstance(reactContext)
+}
diff --git a/android/src/turbo/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt b/android/src/turbo/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt
index 4d99de4b85..060aeeac78 100644
--- a/android/src/turbo/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt
+++ b/android/src/turbo/java/com/reactnativekeyboardcontroller/KeyboardControllerPackage.kt
@@ -59,5 +59,6 @@ class KeyboardControllerPackage : TurboReactPackage() {
KeyboardControllerViewManager(reactContext),
KeyboardGestureAreaViewManager(reactContext),
OverKeyboardViewManager(reactContext),
+ KeyboardToolbarExcludeViewManager(reactContext),
)
}
diff --git a/docs/docs/api/components/keyboard-toolbar/index.mdx b/docs/docs/api/components/keyboard-toolbar/index.mdx
index d0fbaee09a..8e3c124df2 100644
--- a/docs/docs/api/components/keyboard-toolbar/index.mdx
+++ b/docs/docs/api/components/keyboard-toolbar/index.mdx
@@ -295,6 +295,26 @@ const theme: KeyboardToolbarProps["theme"] = {
Don't forget that you need to specify colors for **both** `dark` and `light` theme. The theme will be selected automatically based on the device preferences.
:::
+## Components
+
+### `KeyboardToolbar.Exclude`
+
+This component is used to exclude some views from the traversal. It is useful when you want to skip specific view from being focused by toolbar arrow buttons.
+
+```tsx
+
+
+
+
+
+```
+
## Example
```tsx
diff --git a/example/src/screens/Examples/Toolbar/index.tsx b/example/src/screens/Examples/Toolbar/index.tsx
index a8d9d2b324..101f2a6205 100644
--- a/example/src/screens/Examples/Toolbar/index.tsx
+++ b/example/src/screens/Examples/Toolbar/index.tsx
@@ -154,6 +154,16 @@ function Form() {
title="Flat"
onFocus={onHideAutoFill}
/>
+
+
+
+#else
+#import
+#endif
+#import
+#import
+
+@interface KeyboardToolbarExcludeViewManager : RCTViewManager
+@end
+
+@interface KeyboardToolbarExcludeView :
+#ifdef RCT_NEW_ARCH_ENABLED
+ RCTViewComponentView
+#else
+ UIView
+
+- (instancetype)initWithBridge:(RCTBridge *)bridge;
+
+#endif
+@end
diff --git a/ios/views/KeyboardToolbarExcludeViewManager.mm b/ios/views/KeyboardToolbarExcludeViewManager.mm
new file mode 100644
index 0000000000..46fda7bdd4
--- /dev/null
+++ b/ios/views/KeyboardToolbarExcludeViewManager.mm
@@ -0,0 +1,88 @@
+//
+// KeyboardToolbarExcludeViewManager.mm
+// react-native-keyboard-controller
+//
+// Created by Kiryl Ziusko on 26/12/2024.
+//
+
+#import "KeyboardToolbarExcludeViewManager.h"
+
+#ifdef RCT_NEW_ARCH_ENABLED
+#import
+#import
+#import
+#import
+
+#import "RCTFabricComponentsPlugins.h"
+#endif
+
+#import
+
+#ifdef RCT_NEW_ARCH_ENABLED
+using namespace facebook::react;
+#endif
+
+// MARK: Manager
+@implementation KeyboardToolbarExcludeViewManager
+
+RCT_EXPORT_MODULE(KeyboardToolbarExcludeViewManager)
+
++ (BOOL)requiresMainQueueSetup
+{
+ return NO;
+}
+
+#ifndef RCT_NEW_ARCH_ENABLED
+- (UIView *)view
+{
+ return [[KeyboardToolbarExcludeView alloc] initWithBridge:self.bridge];
+}
+#endif
+
+@end
+
+// MARK: View
+#ifdef RCT_NEW_ARCH_ENABLED
+@interface KeyboardToolbarExcludeView ()
+@end
+#endif
+
+@implementation KeyboardToolbarExcludeView {
+}
+
+#ifdef RCT_NEW_ARCH_ENABLED
++ (ComponentDescriptorProvider)componentDescriptorProvider
+{
+ return concreteComponentDescriptorProvider();
+}
+#endif
+
+// Needed because of this: https://github.com/facebook/react-native/pull/37274
++ (void)load
+{
+ [super load];
+}
+
+// MARK: Constructor
+#ifdef RCT_NEW_ARCH_ENABLED
+- (instancetype)init
+{
+ self = [super init];
+ return self;
+}
+#else
+- (instancetype)initWithBridge:(RCTBridge *)bridge
+{
+ self = [super init];
+ return self;
+}
+#endif
+
+#ifdef RCT_NEW_ARCH_ENABLED
+Class KeyboardToolbarExcludeViewCls(void)
+{
+ return KeyboardToolbarExcludeView.class;
+}
+#endif
+
+@end
diff --git a/src/bindings.native.ts b/src/bindings.native.ts
index d1621d1838..b5267dcb5e 100644
--- a/src/bindings.native.ts
+++ b/src/bindings.native.ts
@@ -60,3 +60,5 @@ export const KeyboardGestureArea: React.FC =
: ({ children }: KeyboardGestureAreaProps) => children;
export const RCTOverKeyboardView: React.FC =
require("./specs/OverKeyboardViewNativeComponent").default;
+export const RCTKeyboardToolbarExcludeView: React.FC =
+ require("./specs/KeyboardToolbarExcludeViewNativeComponent").default;
diff --git a/src/bindings.ts b/src/bindings.ts
index a82850206a..45fd24416f 100644
--- a/src/bindings.ts
+++ b/src/bindings.ts
@@ -6,6 +6,7 @@ import type {
KeyboardControllerProps,
KeyboardEventsModule,
KeyboardGestureAreaProps,
+ KeyboardToolbarExcludeViewProps,
OverKeyboardViewProps,
WindowDimensionsEventsModule,
} from "./types";
@@ -40,3 +41,5 @@ export const KeyboardGestureArea =
View as unknown as React.FC;
export const RCTOverKeyboardView =
View as unknown as React.FC;
+export const RCTKeyboardToolbarExcludeView =
+ View as unknown as React.FC;
diff --git a/src/components/KeyboardToolbar/index.tsx b/src/components/KeyboardToolbar/index.tsx
index dd4e969112..f57253bc45 100644
--- a/src/components/KeyboardToolbar/index.tsx
+++ b/src/components/KeyboardToolbar/index.tsx
@@ -1,7 +1,10 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { StyleSheet, Text, View } from "react-native";
-import { FocusedInputEvents } from "../../bindings";
+import {
+ FocusedInputEvents,
+ RCTKeyboardToolbarExcludeView,
+} from "../../bindings";
import { KeyboardController } from "../../module";
import useColorScheme from "../hooks/useColorScheme";
import KeyboardStickyView from "../KeyboardStickyView";
@@ -71,11 +74,15 @@ const TEST_ID_KEYBOARD_TOOLBAR_DONE = `${TEST_ID_KEYBOARD_TOOLBAR}.done`;
const KEYBOARD_TOOLBAR_HEIGHT = 42;
const DEFAULT_OPACITY: HEX = "FF";
+type KeyboardToolbarComponent = {
+ Exclude: typeof RCTKeyboardToolbarExcludeView;
+} & React.FC;
+
/**
* `KeyboardToolbar` is a component that is shown above the keyboard with `Prev`/`Next` and
* `Done` buttons.
*/
-const KeyboardToolbar: React.FC = ({
+const KeyboardToolbar: KeyboardToolbarComponent = ({
content,
theme = colors,
doneText = "Done",
@@ -222,6 +229,8 @@ const KeyboardToolbar: React.FC = ({
);
};
+KeyboardToolbar.Exclude = RCTKeyboardToolbarExcludeView;
+
const styles = StyleSheet.create({
flex: {
flex: 1,
diff --git a/src/specs/KeyboardToolbarExcludeViewNativeComponent.ts b/src/specs/KeyboardToolbarExcludeViewNativeComponent.ts
new file mode 100644
index 0000000000..bf6c612caf
--- /dev/null
+++ b/src/specs/KeyboardToolbarExcludeViewNativeComponent.ts
@@ -0,0 +1,10 @@
+import codegenNativeComponent from "react-native/Libraries/Utilities/codegenNativeComponent";
+
+import type { HostComponent } from "react-native";
+import type { ViewProps } from "react-native/Libraries/Components/View/ViewPropTypes";
+
+export interface NativeProps extends ViewProps {}
+
+export default codegenNativeComponent(
+ "KeyboardToolbarExcludeView",
+) as HostComponent;
diff --git a/src/types.ts b/src/types.ts
index 0ec0e48be5..130a423112 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -118,6 +118,7 @@ export type KeyboardGestureAreaProps = {
export type OverKeyboardViewProps = PropsWithChildren<{
visible: boolean;
}>;
+export type KeyboardToolbarExcludeViewProps = ViewProps;
export type Direction = "next" | "prev" | "current";
export type DismissOptions = {