DEV Community

debadeepsen
debadeepsen

Posted on • Edited on

Making sliding tabs in React Native

Sliding tab bars are used in the Facebook app, so I was thinking, why not try to do the same in React Native, especially considering that is what they used to build the Facebook app? I quickly realized that I could achieve this using a View that was hidden partially, off-screen, and then using animation to translate it along the X-direction, to move the other parts of the view into place as and when needed. For this, I used the Animated library, and the translateX property of transform. What we're doing is, binding that property to the value of slideAnim, which changes when we press the tab buttons. I'm not covering the basics of Animated here, you can find that in the official docs - https://reactnative.dev/docs/animated . In fact, this example below has been made by slightly modifying the code in the docs. Without further ado, here's the full code.

import React, {useRef} from 'react'; import { Animated, Text, View, StyleSheet, TouchableOpacity, Dimensions, } from 'react-native'; const windowWidth = Dimensions.get('window').width; const windowHeight = Dimensions.get('window').height; const TestPage = () => { const slideAnim = useRef(new Animated.Value(0)).current; const selectTab = (tabIndex) => { Animated.timing(slideAnim, { toValue: -windowWidth * tabIndex, duration: 300, useNativeDriver: true, }).start(); }; return ( <> <View> <Animated.View style={{flexDirection: 'row', transform: [{translateX: slideAnim}]}}> <FirstTab /> <SecondTab /> <ThirdTab /> </Animated.View> </View> <View style={styles.buttonRow}> <TouchableOpacity style={styles.tabButton} onPress={() => { selectTab(0); }}> <Text>One</Text> </TouchableOpacity> <TouchableOpacity style={styles.tabButton} onPress={() => { selectTab(1); }}> <Text>Two</Text> </TouchableOpacity> <TouchableOpacity style={styles.tabButton} onPress={() => { selectTab(2); }}> <Text>Three</Text> </TouchableOpacity> </View> </> ); }; const FirstTab = () => ( <View style={styles.tabBox}> <Text style={styles.caption}>First Tab</Text> <Text style={styles.text}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed dignissim nulla ac mauris condimentum volutpat. In at tincidunt dolor. Pellentesque eu congue turpis. Integer viverra quam neque, id imperdiet dui laoreet id. Vestibulum dapibus velit non tortor congue scelerisque. Aliquam sed tempor nibh. Nam id eros in ex commodo pulvinar nec in erat. Fusce sodales eget felis accumsan fermentum. Aliquam a arcu mattis, consequat dui in, rhoncus arcu. Aenean sollicitudin semper diam eu aliquet. Donec dignissim fermentum feugiat. Curabitur commodo viverra elit, ut elementum nisl gravida vitae. Morbi lobortis luctus dictum. Fusce ornare luctus arcu sit amet ultrices. Donec nec ipsum in quam condimentum tempor aliquam id tortor. In pharetra orci non eros hendrerit dapibus. Aliquam erat volutpat. Nunc blandit dui id augue consequat eleifend. Phasellus et molestie felis, vitae accumsan mauris. Vivamus diam ligula, malesuada vel eros et, sodales scelerisque purus. Aenean at mi eget lectus mollis facilisis a vel lacus. Sed facilisis mauris nec facilisis lobortis. Donec augue erat, volutpat a diam a, dictum mattis eros. </Text> </View> ); const SecondTab = () => ( <View style={styles.tabBox}> <Text style={styles.caption}>Second Tab</Text> <Text style={styles.text}> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. </Text> </View> ); const ThirdTab = () => ( <View style={styles.tabBox}> <Text style={styles.caption}>Third Tab</Text> <Text style={styles.text}> At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat. </Text> </View> ); const styles = StyleSheet.create({ tabBox: { padding: 10, backgroundColor: '#ffe8', height: windowHeight, }, caption: { fontSize: 28, textAlign: 'center', margin: 10, }, buttonRow: { flexDirection: 'row', position: 'absolute', bottom: 0, }, tabButton: { padding: 15, backgroundColor: '#fff', flex: 1, margin: 1, width: 100, justifyContent: 'center', alignItems: 'center', }, text: { textAlign: 'justify', }, }); export default TestPage; 

See it on Snack here - https://snack.expo.io/pi0WJYfSN

The great thing is, because we're translating by a value of windowWidth * tabIndex every time, it's completely dynamic. So you could have as many or as few tabs here as possible, and everything will still work.

Top comments (0)