diff --git a/README.md b/README.md
index 0f92b78..824ee84 100644
--- a/README.md
+++ b/README.md
@@ -83,6 +83,7 @@ function Example() {
// disableSwipe={false} // (default=false) disable swipe to left/right gestures
// tabHeaderStyle // style object, can be animated properties as well in
// tabLabelStyle // style object
+ // TabHeaderComponent={MyCustomHeader} // render a custom header
>
@@ -103,6 +104,7 @@ function Example() {
// onPress={() => {
// console.log('onPress explore');
// }}
+ // TabHeaderComponent={MyCustomHeader} // render a custom header
>
diff --git a/src/Swiper.native.tsx b/src/Swiper.native.tsx
index aa405df..58286e1 100644
--- a/src/Swiper.native.tsx
+++ b/src/Swiper.native.tsx
@@ -26,6 +26,7 @@ function SwiperNative(props: SwiperProps) {
disableSwipe,
tabHeaderStyle,
tabLabelStyle,
+ TabHeaderComponent,
} = props;
const { index, goTo } = React.useContext(TabsContext);
const indexRef = React.useRef(index || 0);
@@ -82,6 +83,7 @@ function SwiperNative(props: SwiperProps) {
mode,
tabHeaderStyle,
tabLabelStyle,
+ TabHeaderComponent,
};
return (
<>
diff --git a/src/Swiper.tsx b/src/Swiper.tsx
index d3e80d6..ca776a3 100644
--- a/src/Swiper.tsx
+++ b/src/Swiper.tsx
@@ -17,6 +17,7 @@ function Swiper(props: SwiperProps) {
mode,
tabHeaderStyle,
tabLabelStyle,
+ TabHeaderComponent,
} = props;
const index = useTabIndex();
@@ -41,6 +42,7 @@ function Swiper(props: SwiperProps) {
mode,
tabHeaderStyle,
tabLabelStyle,
+ TabHeaderComponent,
};
return (
diff --git a/src/TabScreen.tsx b/src/TabScreen.tsx
index 4e10082..8285538 100644
--- a/src/TabScreen.tsx
+++ b/src/TabScreen.tsx
@@ -1,5 +1,6 @@
import * as React from 'react';
import type { GestureResponderEvent } from 'react-native';
+import type TabsHeaderItem from './TabsHeaderItem';
export interface TabScreenProps {
label: string;
@@ -9,6 +10,7 @@ export interface TabScreenProps {
onPress?: (event: GestureResponderEvent) => void;
onPressIn?: (event: GestureResponderEvent) => void;
disabled?: boolean;
+ TabHeaderComponent?: typeof TabsHeaderItem | undefined;
}
export default function TabScreen({ children }: TabScreenProps) {
diff --git a/src/Tabs.tsx b/src/Tabs.tsx
index 3be6a3f..a1c0e88 100644
--- a/src/Tabs.tsx
+++ b/src/Tabs.tsx
@@ -5,6 +5,7 @@ import Swiper from './Swiper';
import type { MD3LightTheme } from 'react-native-paper';
import type { IconPosition, Mode } from './utils';
+import type TabsHeaderItem from './TabsHeaderItem';
function Tabs({
theme,
@@ -18,6 +19,7 @@ function Tabs({
disableSwipe = false,
tabHeaderStyle,
tabLabelStyle,
+ TabHeaderComponent,
...rest
}: {
children: any;
@@ -32,6 +34,7 @@ function Tabs({
disableSwipe?: boolean;
tabHeaderStyle?: ViewStyle | undefined;
tabLabelStyle?: TextStyle | undefined;
+ TabHeaderComponent?: typeof TabsHeaderItem;
}) {
const children = React.Children.toArray(rest.children).filter(Boolean);
@@ -48,6 +51,7 @@ function Tabs({
disableSwipe={disableSwipe}
tabHeaderStyle={tabHeaderStyle}
tabLabelStyle={tabLabelStyle}
+ TabHeaderComponent={TabHeaderComponent}
>
{children}
diff --git a/src/TabsHeader.tsx b/src/TabsHeader.tsx
index 1dd29e3..36ad40c 100644
--- a/src/TabsHeader.tsx
+++ b/src/TabsHeader.tsx
@@ -27,6 +27,7 @@ export default function TabsHeader({
mode,
tabHeaderStyle,
tabLabelStyle,
+ TabHeaderComponent,
children,
}: SwiperRenderProps) {
const { index, goTo } = React.useContext(TabsContext);
@@ -174,7 +175,6 @@ export default function TabsHeader({
style={[
{ backgroundColor, elevation },
restStyle,
- styles.tabs,
iconPosition === 'top' && styles.tabsTopIcon,
]}
onLayout={onTabsLayout}
@@ -218,6 +218,7 @@ export default function TabsHeader({
showTextLabel={showTextLabel}
mode={mode}
tabLabelStyle={tabLabelStyle}
+ TabHeaderComponent={TabHeaderComponent}
/>
))}
;
tabIndex: number;
@@ -48,6 +49,7 @@ export default function TabsHeaderItem({
showTextLabel?: boolean;
mode: Mode;
tabLabelStyle?: TextStyle | undefined;
+ TabHeaderComponent?: typeof TabsHeaderItem;
}) {
const baseColor = theme.colors.primary;
const rippleColor = React.useMemo(
@@ -74,6 +76,99 @@ export default function TabsHeaderItem({
const badgeWithoutContent = typeof tab.props.badge === 'boolean';
+ const CustomHeader = tab.props.TabHeaderComponent || TabHeaderComponent;
+
+ const HeaderItem = CustomHeader ? (
+ }
+ active={active}
+ onTabLayout={onTabLayout}
+ goTo={goTo}
+ activeColor={activeColor}
+ textColor={textColor}
+ position={position}
+ offset={offset}
+ childrenCount={childrenCount}
+ uppercase={uppercase}
+ iconPosition={iconPosition}
+ showTextLabel={showTextLabel}
+ mode={mode}
+ tabLabelStyle={tabLabelStyle}
+ />
+ ) : (
+ <>
+ {tab.props.icon ? (
+
+ {tab.props.icon ? (
+ Platform.OS === 'android' ? (
+
+
+
+ ) : (
+
+ )
+ ) : null}
+
+ ) : null}
+ {badgeIsFilled ? (
+
+ {badgeWithoutContent ? (
+
+ ) : (
+
+ {tab.props.badge as any}
+
+ )}
+
+ ) : null}
+ {showTextLabel ? (
+
+ {uppercase && !theme.isV3
+ ? tab.props.label.toUpperCase()
+ : tab.props.label}
+
+ ) : null}
+ >
+ );
return (
- {tab.props.icon ? (
-
- {tab.props.icon ? (
- Platform.OS === 'android' ? (
-
-
-
- ) : (
-
- )
- ) : null}
-
- ) : null}
- {badgeIsFilled ? (
-
- {badgeWithoutContent ? (
-
- ) : (
-
- {tab.props.badge as any}
-
- )}
-
- ) : null}
- {showTextLabel ? (
-
- {uppercase && !theme.isV3
- ? tab.props.label.toUpperCase()
- : tab.props.label}
-
- ) : null}
+ {HeaderItem}
@@ -188,10 +216,15 @@ const styles = StyleSheet.create({
left: 0,
top: -2,
},
- tabRoot: { position: 'relative' },
+ tabRoot: {
+ position: 'relative',
+ justifyContent: 'center',
+ flexDirection: 'row',
+ alignItems: 'stretch',
+ },
tabRootFixed: { flex: 1 },
touchableRipple: {
- height: 48,
+ minHeight: 48,
justifyContent: 'center',
alignItems: 'center',
overflow: 'hidden',
diff --git a/src/utils.tsx b/src/utils.tsx
index 1c5437b..9db50e9 100644
--- a/src/utils.tsx
+++ b/src/utils.tsx
@@ -8,6 +8,7 @@ import type {
} from 'react-native';
import type { MD3LightTheme } from 'react-native-paper';
import type { MutableRefObject, RefObject } from 'react';
+import type TabsHeaderItem from './TabsHeaderItem';
export type AnimatedViewStyle = Animated.AnimatedProps>;
export type AnimatedTextStyle = Animated.AnimatedProps>;
export type Mode = 'fixed' | 'scrollable';
@@ -27,6 +28,7 @@ export interface SwiperRenderProps {
mode: Mode;
tabHeaderStyle: ViewStyle | undefined;
tabLabelStyle: TextStyle | undefined;
+ TabHeaderComponent?: typeof TabsHeaderItem;
}
export interface SwiperProps {
@@ -42,6 +44,7 @@ export interface SwiperProps {
disableSwipe?: boolean;
tabHeaderStyle: ViewStyle | undefined;
tabLabelStyle: TextStyle | undefined;
+ TabHeaderComponent?: typeof TabsHeaderItem;
}
export interface OffsetScrollArgs {