UNPKG

react-native-modern-elements

Version:

A modern, customizable UI component library for React Native

1,100 lines (1,002 loc) β€’ 28.2 kB
# react-native-modern-elements Modern, customizable, and production-ready UI components for React Native & Expo. ## <img src="https://raw.githubusercontent.com/nizamuddin15bd/MyAllPackagesDemoImage/refs/heads/main/reactnativemodernelements.png" alt="react-native-beauty-tabs image" width="auto" height="300" /> ## Demo Screenshot ## <img src="https://raw.githubusercontent.com/nizamuddin15bd/MyAllPackagesDemoImage/refs/heads/main/firstdemo.png" alt="react-native-beauty-tabs image" width="auto" height="400" /> <img src="https://raw.githubusercontent.com/nizamuddin15bd/MyAllPackagesDemoImage/refs/heads/main/seconddemo.png" alt="react-native-beauty-tabs image" width="auto" height="400" /> ## Features - Built for Expo & React Native - Smooth animations - Fully customizable tabs and styling - Icon support for each tab - Dynamic width ratio support --- ## πŸ±β€πŸ Coming Soon πŸ”„ Exciting new features are on the way! πŸ› οΈ Planned updates include fresh **hooks** and **components** with improved performance. 1. Data Fetching usePaganation hook 2. Carousel 3. ImageStack 4. Tabs --- ## Connect with me - 🌐 [Portfolio Website](https://www.expertsquad.net) - ✨ [Facebook](https://www.facebook.com/naem.nizam.2024) - πŸ’» [GitHub](https://github.com/nizamuddin15bd) --- ## Best Practices . If you encounter an error, stop the Terminal and run the project again. --- ## Components List . [βœ…] Modals . [βœ…] BottomSheet . [βœ…] SelectList . [βœ…] Popup . [βœ…] RangeSlider . [βœ…] RadialProgress . [βœ…] RadioCircle . [βœ…] Table . [βœ…] OTPInput . [βœ…] Toast . [βœ…] InternetStatusToast . [βœ…] Input . [βœ…] Button . [βœ…] CheckBox . [βœ…] Switch . [βœ…] StarRating . [βœ…] NumberCount . [βœ…] Typo . [βœ…] Divider . [βœ…] useBackExit . [βœ…] useScrollShadowAnimation . [βœ…] TabSlider . [βœ…] ExpandableText --- ## Installation ```bash npm install react-native-modern-elements # or yarn add react-native-modern-elements ``` ## πŸ§ͺ Example Usage ## Modals Usage ```tsx import React from "react"; import { TouchableOpacity, View, Text } from "react-native"; import { Modals } from "react-native-modern-elements"; const ModalsUsing = () => { const [modalVisible, setModalVisible] = React.useState(false); const handleShowProduct = (product: any) => { setModalVisible(product); }; return ( <View> <TouchableOpacity onPress={() => setModalVisible(true)} style={styles.openButton} > <Text style={styles.buttonText}>Open Modal</Text> </TouchableOpacity> <Modals visible={modalVisible} animation="LeftToCenterCloseToRight" onClose={() => setModalVisible(false)} modalContainer={{ width: "90%", height: verticalScale(250), paddingHorizontal: verticalScale(20), paddingTop: verticalScale(20), paddingBottom: verticalScale(17), }} > <View style={{ alignItems: "center" }}> <View style={styles.header}> <TouchableOpacity onPress={() => setModalVisible(false)}> <Text className="font-bold text-3xl">X</Text> </TouchableOpacity> </View> </View> <View className="w-[150px] h-[150px] rounded-full bg-secondary-light self-center flex justify-center items-center"> <Text className="font-medium text-3xl text-center text-white "> Success </Text> </View> <Text className="text-center mt-4"> Congratulations registration was successful </Text> </Modals> </View> ); }; export default ModalsUsing; const styles = StyleSheet.create({ header: { width: "100%", height: 40, alignItems: "flex-end", }, openButton: { backgroundColor: "#F194FF", borderRadius: 20, padding: 10, elevation: 2, }, buttonText: { color: "white", fontWeight: "bold", textAlign: "center", }, }); ``` ## BottomSheet Usage ```tsx import { colors } from "@/src/constants/theme"; import { verticalScale } from "@/src/utils/styling"; import React from "react"; import { Text, TouchableOpacity, View } from "react-native"; import CancelIcon from "@/src/assets/svg/CancelIcon"; import { BottomSheet, BottomSheetHandle, Input, Divider, Button, } from "react-native-modern-elements"; const BottomSheet = () => { const refScrollable = React.useRef<BottomSheetHandle>(null); const showUpdatedPasswordbs = () => { refScrollable.current?.open(); }; return ( <View className="-mt-48"> <TouchableOpacity onPress={() => refScrollable.current?.open()} style={{ backgroundColor: "blue", padding: 10, borderRadius: 5, marginTop: 10, }} > <Text style={{ color: "white" }}>BottomSheet</Text> </TouchableOpacity> <BottomSheet ref={refScrollable} // snapPoints={snapPoints} snapPoints={["30%", "50%"]} draggable // dragOnContent closeOnPressBack={false} closeOnPressMask={false} wrapperColors={{ backgroundColor: "transparent" }} defaultOpen={true} showIndicator={true} mainContainer={{ backgroundColor: "white", shadowColor: "gray", elevation: 20, shadowRadius: 10, borderTopRightRadius: 0, borderTopLeftRadius: 0, }} // openDuration={310} > <ViewWrapper style={{ width: "90%", alignSelf: "center", // height: verticalScale(440), }} > {/* header */} <View className="flex-row items-center justify-between"> <Text>UpdatedPasswordBS</Text> <TouchableOpacity onPress={() => refScrollable.current?.close()} className="w-16 h-10 flex-row items-center justify-end " > <CancelIcon /> </TouchableOpacity> </View> </ViewWrapper> <Divider align="center" mt={14} mb={20} bg={colors?.black_10} /> <ViewWrapper style={{ width: "90%", alignSelf: "center", height: verticalScale(335), }} > <View className="flex-col items-center justify-center gap-6"> <Input lable="Current Password" lableStyle={{ color: colors?.black_70, fontSize: 14 }} placeholder="Password" secureTextEntry containerStyle={{ borderRadius: 50, backgroundColor: colors.black_10, overflow: "hidden", }} iconStyle={{ marginLeft: verticalScale(4) }} /> <Input lable="New Password" lableStyle={{ color: colors?.black_70, fontSize: 14 }} placeholder="New Password" secureTextEntry containerStyle={{ borderRadius: 50, backgroundColor: colors.black_10, overflow: "hidden", }} iconStyle={{ marginLeft: verticalScale(4) }} /> <Input lable="Re-type New Password" lableStyle={{ color: colors?.black_70, fontSize: 14 }} placeholder="Re-type New Password" secureTextEntry containerStyle={{ borderRadius: 50, backgroundColor: colors.black_10, overflow: "hidden", }} iconStyle={{ marginLeft: verticalScale(4) }} /> </View> <Button className="bg-primary py-4 rounded-3xl absolute bottom-0 w-full"> <Text className="text-white font-medium">Update Password</Text> </Button> </ViewWrapper> </BottomSheet> </View> ); }; export default BottomSheet; ``` ## Table Usage ```tsx import { colors } from "@/src/constants/theme"; import React from "react"; import { Text, View } from "react-native"; import { Table, Divider } from "react-native-modern-elements"; const TableUsing = () => { const [data, setData] = React.useState<any[]>([]); React.useEffect(() => { const url = "https://api.escuelajs.co/api/v1/products"; fetch(url) .then((res) => res.json()) .then((data) => { const limitedData = data?.slice(0, 20); setData(limitedData); }); }, []); return ( <ScreenWrapper StatusBarColor={colors.green} barStyle="dark-content" style={{ flex: 1, alignItems: "center", justifyContent: "center", padding: 16, }} > <Table height={500} borderColor={colors?.black_5} borderWidth={0.7} // Refreshing headerborderRight={true} cellRowBottomBorder={true} cellRowRightBorder={true} enableHeaderShadow={true} headerborderBottom={true} // showHeader tableStyles={{ borderTopRightRadius: 10, borderTopLeftRadius: 10, borderBottomRightRadius: 5, borderBottomLeftRadius: 5, borderWidth: 1, borderColor: colors?.black_15, }} contentContainerStyle={{ paddingBottom: 200 }} divider={true} // dividerHeight={0.7} // dividerColors={colors?.black_5} dividerWight={"100%"} headerShadowStyle={{ shadowColor: "purple", shadowOpacity: 0.3, shadowOffset: { width: 0, height: 3 }, shadowRadius: 5, elevation: 6, }} cellRowStyle={{ paddingHorizontal: 10, paddingVertical: 10, flexDirection: "row", }} showsVerticalScrollIndicator={false} HeaderRowStyle={{ backgroundColor: colors?.black_10 }} headerTexts={{ fontSize: 16, fontWeight: "500", paddingVertical: 2, color: colors?.black_70, }} onRowPress={(item, rowIndex) => { router.push("/(screens)/(tabs)/account"); }} // data={users} data={data} defaultAlign="left" // Global text alignment for all columns columns={[ { label: "Product", key: "Product", // Control width of this column align: "left", // Override defaultAlign at the column level headerTextAlign: "left", render: (value, hello) => ( <View style={{ flexDirection: "row", alignItems: "center", justifyContent: "center", }} > <ImageStack maxDisplayImage={1} images={hello?.images} containerStyle={{ flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 5, }} imageWrapperStyle={{ borderRadius: 20 }} imageContainerStyle={{ height: 25, width: 25, // borderRadius: 20, }} /> </View> ), headerStyle: { // backgroundColor: "#f0f8ff", flex: 3, }, }, { label: "Quantity", key: "email", align: "center", // Override defaultAlign at the column level // headerTextAlign: "left", headerStyle: { // backgroundColor: "#f0f8ff", flex: 2, }, render: (value, row, rowIndex) => ( <View style={{ flexDirection: "column", alignItems: "center", justifyContent: "center", }} > <Text style={{ textAlign: "center" }}>{row?.price}</Text> </View> ), }, { label: "Age", key: "age", align: "center", // Override defaultAlign at the column level headerStyle: { // backgroundColor: "#f0f8ff", flex: 2, }, render: (value, row, rowIndex) => ( <View style={{ flexDirection: "column", alignItems: "center", justifyContent: "center", }} > <Text style={{ fontSize: 14, textAlign: "center" }}> $5,000 </Text> </View> ), }, ]} summary={{ align: "right", content: ( <View style={{ padding: 5, gap: 6, }} > <Text style={{ fontWeight: "400", fontStyle: "italic", fontSize: 18, color: colors.black_50, }} > Summary </Text> <Divider width={"100%"} height={0.5} /> <View style={{ gap: 3 }}> <View className="flex-row justify-between items-center"> <Text>Total Item</Text> <Text>60 item</Text> </View> <View className="flex-row justify-between items-center"> <Text className="text-black-70">Total Item</Text> <Text>$20,000</Text> </View> </View> </View> ), style: { backgroundColor: colors.black_10, width: "80%", // height: 300, borderRadius: 10, }, }} /> <View className="py-3 px-3 bg-white"> <Text>hello</Text> </View> </ScreenWrapper> ); }; export default TableUsing; ``` ## OTPInput Usage ```tsx import { OTPInput } from "react-native-modern-elements"; const [otp, setOtp] = useState<number | null>(null); <View> {/* OTPInput component updates the `otp` state correctly */} <OTPInput length={4} setVerifyOtp={(val) => setOtp(parseInt(val.join("")))} /> </View>; ``` ## StarRating Usage ```tsx import { StarRating } from "react-native-modern-elements"; <StarRating rating={4.6} size={20} startgap={2} activeStartColor={colors?.rose} inActiveStartColor={colors?.green} />; ``` ## RadialProgress Usage ```tsx import { StarRating } from "react-native-modern-elements"; <RadialProgress percentage={50} Radialsize={150} strokeLinecap="round" strokeWidths={12} percentageTextSize={20} percentageTextFontWeight={"600"} animationDuration={1000} color={{ high: "green-medium", low: "red", medium: "yellow", veryHigh: "green", }} />; ``` ## NumberCount Usage ```tsx import { NumberCount } from "react-native-modern-elements"; <NumberCount end={930000} formatPrice locale="en-US" prefix="$" style={{ fontSize: verticalScale(28), fontWeight: "800", color: colors?.black, }} />; ``` ## SelectList Usage ```tsx import { SelectList } from "react-native-modern-elements"; const [selected, setSelected] = React.useState<string | null>(null); const data = [ { key: "1", value: "desc", modallable: "Recently", icons: <CheckboxIconSvg />, }, { key: "2", value: "asc", modallable: "Oldest", icons: <CheckboxIconSvg />, }, ]; const handleSelectItem = (item: string) => { setSelected(item); // Set selected item }; <View className="w-[50%]"> <SelectList lable=" SelectList" searchPlaceholder="Search ..." // maxHeight={300} // setSelected={(val) => setSelected(val)} setSelected={handleSelectItem} fontFamily="lato" data={data as any} DefaultTitle="Sort by" maxHeight={160} Reset selectedIcons={false} searchicon={false} search={true} dropdownTextStyles={{ fontStyle: "italic" }} dropdownItemStyles={{ paddingHorizontal: 20, paddingVertical: 10, borderBottomColor: colors?.black_10, borderBottomWidth: 0.7, }} InputboxStyles={{ borderRadius: 10, height: 50, backgroundColor: colors?.white, paddingHorizontal: 10, }} //override default styles // defaultOption={{ key: "1", value: "Sort by" }} //default selected option onSelect={() => {}} save="value" dropdownShown={false} dropdownShadow={true} /> </View>; ``` ## Popup Usage ```tsx import { Popup } from "react-native-modern-elements"; const [selected, setSelected] = React.useState<string | null>(null); const handleSelectItem = (item: string) => { console.log("handleSelectItem", item); setSelected(item); }; <Popup data={[ { key: 1, value: "Apple", modallable: "🍎 Apple" }, { key: 2, value: "Banana", modallable: "🍌 Banana" }, { key: 3, value: "Cherry", modallable: "πŸ’ Cherry" }, ]} save="key" setSelected={(val) => handleSelectItem(key)} setSelected={(val) => setSelected(val)} save="value" maxHeight={130} // maxWidth={150} // gap={8} // popupShown={dropdownShown} // pass state down // setPopupShown={setDropdownShown} // pass updater popupShadow={true} animation="updown" popupBoxStyle={{ paddingVertical: 0, paddingHorizontal: 0, // backgroundColor: colors?.green, }} renderButton={(toggle, selected) => ( <TouchableOpacity onPress={toggle} style={{ flexDirection: "row", width: 120, height: 45, alignItems: "center", justifyContent: "space-between", padding: 12, backgroundColor: "#fff", borderWidth: 1, borderColor: "#ddd", borderRadius: 8, }} > <Text>{selected || "Select a Popup"}</Text> </TouchableOpacity> )} />; ``` ## RadioCircle Using ```tsx import { RadioCircle } from "react-native-modern-elements"; const [isOn, setIsOn] = useState(false); // true = ON, false = OFF const [selected, setSelected] = useState("apple"); <RadioCircle value="apple" selected={selected} onSelect={setSelected} circleSize={24} circleColor="green" selectedColor="green" activeDotSize={16} containerStyle={{ marginVertical: 8, borderWidth: 1 }} />; <RadioCircle type="two" value="Nizam" selected={selected} onSelect={setSelected} circleSize={35} circleBorderWidth={2} circleColor="#ff0000" selectedColor="#ff0000" activeDotSize={24} // <-- control active dot width containerStyle={{ marginVertical: 8 }} /> <RadioCircle value="toggle" type="one" selected={isOn ? "toggle" : ""} // toggle selected state onSelect={() => setIsOn(!isOn)} // flip state circleSize={30} circleBorderWidth={2} circleColor={isOn ? "green" : "gray"} selectedColor="green" activeDotSize={18} containerStyle={{ marginVertical: 10 }} />; ``` ## Switch Usage ```tsx import { Switch } from "react-native-modern-elements"; <Switch // value={isActive} onValueChange={(newValue) => { // toggleConnection(item?.id, newValue); // revalidateManager.run(`/delivery-company`); console.log("newValue", newValue); }} // disabled={isActive === false ? false : !isActive ? true : false} activeColor="green" inactiveColor="gray" switchContainers={{ width: verticalScale(55), height: verticalScale(25), }} switchCircle={{ width: verticalScale(20), height: verticalScale(20), }} switchTexts={{ fontSize: verticalScale(10), fontWeight: "800", }} />; ``` ## RangeSlider Usage ```tsx import { RangeSlider } from "react-native-modern-elements"; const MIN_DEFAULT = 500; const MAX_DEFAULT = 10500; const minRef = React.useRef(MIN_DEFAULT); const maxRef = React.useRef(MAX_DEFAULT); <RangeSlider sliderWidth={300} defaultLeftPercent={0.15} // 15% defaultRightPercent={0.7} // 70% min={MIN_DEFAULT} max={MAX_DEFAULT} mode="range" step={100} thumbStyle="two" thumbValue="Value" TrackthumbLabelBackgroundColor="green" textColor="blue" fontSize={10} TrackHeight={8} priceSymbols="#" trickBorderRadious={100} onValueChange={(range) => { minRef.current = range?.min; maxRef.current = range?.max; }} />; ``` ## InternetStatusToast and Toast and useBackExit usinge 🀳Your root layout using ```tsx import SplashScreenComponent from "@/src/components/splashScreen/SplashScreenComponent"; import { useFonts } from "expo-font"; import { Stack } from "expo-router"; import * as SplashScreen from "expo-splash-screen"; import { useEffect, useState } from "react"; import { View } from "react-native"; import { Toast, toastRef, useBackExit, InternetStatusToast, } from "react-native-modern-elements"; SplashScreen.preventAutoHideAsync(); export default function RootLayout() { useBackExit(); const [isSplashVisible, setSplashVisible] = useState(true); const [fontsLoaded] = useFonts({ SpaceMono: require("../../assets/fonts/SpaceMono-Regular.ttf"), }); useEffect(() => { if (fontsLoaded) { setTimeout(() => { setSplashVisible(false); SplashScreen.hideAsync(); }, 2500); } }, [fontsLoaded]); if (isSplashVisible) { return <SplashScreenComponent />; } return ( <View style={{ flex: 1 }}> <Stack> <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> {/* <Stack.Screen name="(details)" options={{ headerShown: false }} /> */} </Stack> <> <InternetStatusToast /> <Toast ref={toastRef} defaultAnimation="center" top={50} // customIcons={{ // success: <Success color={colors?.white} />, // error: <ErrorIconSvg color={colors?.white} />, // info: <InfoIconSvg color={colors?.white} />, // }} contentStyle={{ gap: 5 }} width={300} iconSize={20} duration={50000} maxHeight={400} textStyle={{ fontStyle: "italic" }} containerStyle={{ borderRadius: 10, paddingHorizontal: 0, paddingVertical: 0, }} iconColor="yellow" /> </> {/* Show banner globally at bottom */} </View> ); } ``` ## Toast Usage ```tsx import { toastRef } from "react-native-modern-elements"; const handleSubmit = async () => { if (isOffline) { ToastAndroid.show( " Please connect your internet to continue", ToastAndroid.SHORT ); return; } const data = { email: values.email, password: values.password, }; try { setLoading(true); const res = await loginServerAction(data as any); if (res?.data?.accessToken) { // Alert.alert("Login Successful", "You are now logged in."); router.replace("/(screens)/(tabs)"); setLoading(false); // ToastAndroid.show("Login successfully!", ToastAndroid.SHORT); toastRef.current?.show( "Login successfull", "success", "rightToCenterCloseRight" ); } else { handleApiError(res); setLoading(false); } } catch (error) { console.error("Error during form submission:", error); } }; ``` ## CheckBox Usage ```tsx import { CheckBox } from "react-native-modern-elements"; const [checkedItems, setCheckedItems] = useState<{ [key: string]: boolean }>( {} ); <CheckBox checked={isChecked} onChange={(val: boolean) => { setIsChecked(val); }} checkBoxStyle={{ width: 40, height: 40, ...classComponent.borderStyle, }} iconSize={35} // text="Accept Terms" />; ``` ## Button Usage ```tsx import { Button } from "react-native-modern-elements"; <Button disabled={!isFormValid} onPress={handleSubmit} style={{ backgroundColor: isFormValid ? colors.primary : colors.black, opacity: isFormValid ? 1 : 0.6, borderRadius: verticalScale(50), height: verticalScale(46), }} > {loading ? ( <View className="flex-row items-center justify-center gap-2"> <ActivityIndicator color={colors.white} size="small" /> <Typo fontWeight="600" color={colors.white} size={21}> Continue </Typo> </View> ) : ( <Typo fontWeight="600" color={colors.white} size={21}> Continue </Typo> )} </Button>; ``` ## Input Usage ```tsx import { Input } from "react-native-modern-elements"; <Input placeholder="Name" value={values.full_name} onChangeText={(value) => { handleChange("full_name", value); setRef("full_name", value); validateField(value); }} error={errors.full_name || ""} icon={<UserIconSvg color={colors.black_30} />} containerStyle={{ borderRadius: 50, backgroundColor: colors.bgColors, overflow: "hidden", }} iconStyle={{ marginLeft: verticalScale(4) }} />; ``` ## TabSlider Usage ```tsx import { TabSlider } from "react-native-modern-elements"; <TabSlider initialPage={0} renderTabItem={({ tab, isActive, onPress }) => ( <TouchableOpacity onPress={onPress}> <View style={{ flexDirection: "row", alignItems: "center", paddingVertical: 12, paddingHorizontal: 16, borderRadius: 10, backgroundColor: isActive ? "orange" : "#eee", }} > {/* Label */} <Text style={{ color: isActive ? "white" : "black", fontWeight: "600", }} > {tab.label} </Text> {/* Tooltip (if exists) */} {tab.tooltip !== undefined && ( <View style={{ marginLeft: 8, paddingHorizontal: 8, paddingVertical: 2, borderRadius: 14, backgroundColor: isActive ? "white" // tooltipActiveColor alternative : "orange", // tooltipInactiveColor alternative (match your design) }} > <Text style={{ color: isActive ? "black" : "white", fontSize: verticalScale(11), fontWeight: "600", }} > {tab.tooltip} </Text> </View> )} </View> </TouchableOpacity> )} variant="pill" alignTabs="center" // buttonStyle={{ backgroundColor: ac "black", paddingVertical: 14 }} buttonTextStyle={{ color: "white" }} buttonContainerStyle={{ marginHorizontal: 10, }} activeColor="green" inactiveColor="white" tooltipActiveColor="white" tooltipInactiveColor="green" // header={<View style={{ width: 20 }} />} footer={<View style={{ width: 20 }} />} tabs={[ { label: "Newest", tooltip: 20 }, { label: "Top Sell" }, { label: "Popular" }, ]} > <NewestPage /> <TopSellPage /> <PopularPage /> </TabSlider> const styles = StyleSheet.create({ page: { // flex: 1, justifyContent: "center", alignItems: "center", // padding: 20, }, pageText: { fontSize: 24, fontWeight: "bold", }, }); ``` ## ExpandableText Using ```tsx import { ExpandableText } from "react-native-modern-elements"; <ExpandableText textStyle={{ fontSize: verticalScale(13), color: colors?.black_50, lineHeight: 23, letterSpacing: 0.9, textDecorationLine: "underline", }} > Breathe elegance into your summer wardrobe with Zara’s Oversized Linen Blend Shirt in a gentle blush pink tone. </ExpandableText>; ```