├── .gitignore ├── LICENSE ├── README.md ├── package.json └── src ├── SearchableFlatList.js ├── SearchableSectionList.js └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Chandrasekar Gokulanathan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-searchable-list 2 | 3 | A powerful wrapper around React Native FlatList and SectionList to provide built in search feature. 4 | `react-native-searchable-list` is designed to be simple yet a powerful wrapper around react native's FlatList and SectionList components to provide them with search functionality. 5 | 6 | ### Installation 7 | 8 | ```shell 9 | npm i react-native-searchable-list --save 10 | ``` 11 | 12 | ### 1. SearchableFlatList 13 | 14 | #### API 15 | 16 | | Props | Description | Data Type | isRequired | 17 | | ---------------- | ------------------------------------- | ----------------------------------------------------------------------------- | ------------------------ | 18 | | `data` | Data for the FlatList | `Array` | :white_check_mark: | 19 | | `searchTerm` | Searching Term being input by the user. Typically this will be a state variable bound to a text input | `String` | :white_check_mark: | 20 | | `searchAttribute` | Attribute to be searched in case of array of objects. This will be empty in case of a simple array data | `String` | :x: | 21 | | `ignoreCase` | Case sensitive / Case insensitive search. By default this will be set to true | `Boolean` | :x: | 22 | 23 | By default the `SearchableFlatList` also inherits all the props of a React Native `FlatList`. You could use virtually any props you would with a FlatList. 24 | 25 | #### Usage 26 | 27 | ```js 28 | import { SearchableFlatList } from "react-native-searchable-list"; 29 | 30 | {item.name}} 36 | keyExtractor={item => item.id} 37 | /> 38 | ``` 39 | 40 | #### Example 41 | 42 | Github repo with the above examples - https://github.com/Chandrasekar-G/RNSearchableListDemo 43 | 44 | 45 | ##### 1. Simple Array Data 46 | 47 | ![Flat List](https://github.com/Chandrasekar-G/RNSearchableListDemo/blob/master/Assets/FlatList-1.gif) 48 | 49 | ##### Usage 50 | ```js 51 | 52 | this.state = { 53 | data: [ "Taj Mahal", "Great Wall of China", "Machu Picchu", "Christ the Redeemer", "Chichen Itza", "Roman Colosseum", "Petra" ], 54 | searchTerm: "", 55 | searchAttribute: "", 56 | ignoreCase: true 57 | }; 58 | render() { 59 | const { data, searchTerm, searchAttribute, ignoreCase } = this.state; 60 | this.setState({ searchTerm })} /> 63 | 64 | ( {item} )} 68 | keyExtractor={item => item} /> 69 | } 70 | 71 | ``` 72 | ##### 2. Array of Objects 73 | 74 | ![Flat List](https://github.com/Chandrasekar-G/RNSearchableListDemo/blob/master/Assets/FlatList-2.gif) 75 | 76 | ##### Usage 77 | ```js 78 | 79 | this.state = { 80 | data: [ { id: 1, name: "Taj Mahal", country: "India" }, 81 | { id: 2, name: "Great Wall of China", country: "China" }, 82 | { id: 3, name: "Machu Picchu", country: "Peru" }, 83 | { id: 4, name: "Christ the Redeemer", country: "Brazil" }, 84 | { id: 5, name: "Chichen Itza", country: "Mexico" }, 85 | { id: 6, name: "Roman Colosseum", country: "Italy" }, 86 | { id: 7, name: "Petra", country: "Jordan" } ], 87 | searchTerm: "", 88 | searchAttribute: "country", 89 | ignoreCase: true 90 | }; 91 | 92 | render() { 93 | const { data, searchTerm, searchAttribute, ignoreCase } = this.state; 94 | this.setState({ searchTerm })} /> 97 | 98 | ( {item.name} )} 102 | keyExtractor={item => item.id} /> 103 | } 104 | 105 | ``` 106 | 107 | ##### 3. Array of Complex Objects 108 | 109 | ![Flat List](https://github.com/Chandrasekar-G/RNSearchableListDemo/blob/master/Assets/FlatList-3.gif) 110 | 111 | ##### Usage 112 | ```js 113 | 114 | this.state = { 115 | data: [ 116 | { id: 1, name: "Taj Mahal", address: { continent: "Asia", country: "India" } }, 117 | { id: 2, name: "Great Wall of China", address: { continent: "Asia", country: "China" } }, 118 | { id: 3, name: "Machu Picchu", address: { continent: "South America", country: "Peru" } }, 119 | { id: 4, name: "Christ the Redeemer", address: { continent: "South America", country: "Brazil" } }, 120 | { id: 5, name: "Chichen Itza", address: { continent: "South America", country: "Mexico" } }, 121 | { id: 6, name: "Roman Colosseum", address: { continent: "Europe", country: "Italy" } }, 122 | { id: 7, name: "Petra", address: { continent: "Asia", country: "Jordan" } } ], 123 | searchTerm: "", 124 | searchAttribute: "address.continent", 125 | ignoreCase: true 126 | }; 127 | 128 | render() { 129 | const { data, searchTerm, searchAttribute, ignoreCase } = this.state; 130 | this.setState({ searchTerm })} /> 133 | 134 | ( {item.name} )} 139 | keyExtractor={item => item.id} /> 140 | } 141 | ``` 142 | 143 | ### 2. SearchableSectionList 144 | 145 | #### API 146 | 147 | | Props | Description | Data Type | isRequired | 148 | | ---------------- | ------------------------------------- | ----------------------------------------------------------------------------- | ------------------------ | 149 | | `sections` | Data for the SectionList | `Array` | :white_check_mark: | 150 | | `searchTerm` | Searching Term being input by the user. Typically this will be a state variable bound to a text input | `String` | :white_check_mark: | 151 | | `searchByTitle` | Search applies to the title instead of the data is set to true. By default this is set to false | `Boolean` | :x: | 152 | | `searchAttribute` | Attribute to be searched in case of array of objects. This will be empty in case of a simple array data | `String` | :x: | 153 | | `ignoreCase` | Case sensitive / Case insensitive search. By default this will be set to true | `Boolean` | :x: | 154 | 155 | By default the `SearchableSectionList` also inherits all the props of a React Native `SectionList`. You could use virtually any props you would with a `SectionList`. 156 | 157 | #### Usage 158 | 159 | ```js 160 | import { SearchableSectionList } from "react-native-searchable-list"; 161 | 162 | ( {title} )} 169 | renderItem={({ item }) => ( {item} )} 170 | keyExtractor={item => item} 171 | /> 172 | ``` 173 | 174 | #### Example 175 | 176 | Github repo with the above examples - https://github.com/Chandrasekar-G/RNSearchableListDemo 177 | 178 | 179 | ##### 1. Simple Array Data 180 | 181 | ![Section List](https://github.com/Chandrasekar-G/RNSearchableListDemo/blob/master/Assets/SectionList-1.gif) 182 | 183 | ##### Usage 184 | ```js 185 | 186 | this.state = { 187 | data: [ { title: "Asia", data: ["Taj Mahal", "Great Wall of China", "Petra"] }, 188 | { title: "South America", data: ["Machu Picchu", "Christ the Redeemer", "Chichen Itza"] }, 189 | { title: "Europe", data: ["Roman Colosseum"] } ], 190 | searchTerm: "", 191 | searchAttribute: "", 192 | searchByTitle: false, 193 | ignoreCase: true 194 | }; 195 | 196 | render() { 197 | const { data, searchTerm, searchByTitle, searchAttribute, ignoreCase } = this.state; 198 | this.setState({ searchTerm })} /> 201 | 202 | ( 206 | {title} 207 | )} 208 | renderItem={({ item }) => ( 209 | {item} 210 | )} 211 | keyExtractor={item => item} 212 | /> 213 | } 214 | 215 | ``` 216 | ##### 2. Array of Objects 217 | 218 | ![Section List](https://github.com/Chandrasekar-G/RNSearchableListDemo/blob/master/Assets/SectionList-2.gif) 219 | 220 | ##### Usage 221 | ```js 222 | 223 | this.state = { 224 | data: [ { title: "Asia", data: [ { id: 1, name: "Taj Mahal", address: { continent: "Asia", country: "India" } }, 225 | { id: 2, name: "Great Wall of China", address: { continent: "Asia", country: "China" } }, 226 | { id: 7, name: "Petra", address: { continent: "Asia", country: "Jordan" } } ] }, 227 | { title: "South America", data: [ { id: 3, name: "Machu Picchu", address: { continent: "", country: "Peru" } }, 228 | { id: 4, name: "Christ the Redeemer", address: { continent: "South America", country: "Brazil" } }, 229 | { id: 5, name: "Chichen Itza", address: { continent: "South America", country: "Mexico" } } ] }, 230 | { title: "Europe", data: [ { id: 6, name: "Roman Colosseum", address: { continent: "Europe", country: "Italy" } } ] } ], 231 | searchTerm: "", 232 | searchAttribute: "address.country", 233 | ignoreCase: true 234 | }; 235 | 236 | render() { 237 | const { data, searchTerm, searchAttribute, ignoreCase } = this.state; 238 | this.setState({ searchTerm })} /> 241 | 242 | ( 247 | {title} 248 | )} 249 | renderItem={({ item }) => ( 250 | {item.name} 251 | )} 252 | keyExtractor={item => item.id} 253 | /> 254 | } 255 | 256 | ``` 257 | 258 | ##### 3. Search By Title 259 | 260 | ![Section List](https://github.com/Chandrasekar-G/RNSearchableListDemo/blob/master/Assets/SectionList-3.gif) 261 | 262 | ##### Usage 263 | ```js 264 | 265 | this.state = { 266 | data: [ { title: "Asia", data: ["Taj Mahal", "Great Wall of China", "Petra"] }, 267 | { title: "South America", data: ["Machu Picchu", "Christ the Redeemer", "Chichen Itza"] }, 268 | { title: "Europe", data: ["Roman Colosseum"] } ], 269 | searchTerm: "", 270 | searchAttribute: "", 271 | searchByTitle: true, 272 | ignoreCase: true 273 | }; 274 | 275 | render() { 276 | const { data, searchTerm, searchAttribute, ignoreCase } = this.state; 277 | this.setState({ searchTerm })} /> 280 | 281 | ( 286 | {title} 287 | )} 288 | renderItem={({ item }) => ( 289 | {item} 290 | )} 291 | keyExtractor={item => item} 292 | /> 293 | } 294 | ``` 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-searchable-list", 3 | "version": "1.1.2", 4 | "description": "A Wrapper around FlatList and SectionList with search feature.", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/Chandrasekar-G/react-native-searchable-list.git" 12 | }, 13 | "keywords": [ 14 | "react-native", 15 | "flat-list", 16 | "section-list", 17 | "search", 18 | "filter", 19 | "section-list", 20 | "flat-list", 21 | "react-native-search", 22 | "react-native-filter" 23 | ], 24 | "author": "Chandrasekar Gokulanathan", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/Chandrasekar-G/react-native-searchable-list/issues" 28 | }, 29 | "homepage": "https://github.com/Chandrasekar-G/react-native-searchable-list#readme", 30 | "peerDependencies": { 31 | "react": "^16.0.0-alpha.12", 32 | "react-native": "^0.44.0" 33 | }, 34 | "dependencies": {}, 35 | "devDependencies": { 36 | "babel-jest": "23.2.0", 37 | "babel-preset-react-native": "4.0.0", 38 | "jest": "23.2.0", 39 | "react-test-renderer": "16.3.1" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/SearchableFlatList.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { View, Text, FlatList } from "react-native"; 4 | 5 | export default class SearchableFlatList extends Component { 6 | static propTypes = { 7 | data: PropTypes.array.isRequired, 8 | searchTerm: PropTypes.string.isRequired, 9 | searchAttribute: PropTypes.string, 10 | ignoreCase: PropTypes.bool 11 | }; 12 | 13 | static defaultProps = { 14 | searchAttribute: "", 15 | ignoreCase: true 16 | }; 17 | 18 | render() { 19 | const { data, searchAttribute, searchTerm, ignoreCase } = this.props; 20 | return ( 21 | { 24 | let searchData = searchAttribute 25 | ? searchAttribute 26 | .split(".") 27 | .reduce((prevVal, currVal) => prevVal[currVal], tempData) 28 | : tempData; 29 | if (ignoreCase) { 30 | return searchData.toLowerCase().includes(searchTerm.toLowerCase()); 31 | } else { 32 | return searchData.includes(searchTerm); 33 | } 34 | })} 35 | /> 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/SearchableSectionList.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import PropTypes from "prop-types"; 3 | import { View, Text, SectionList } from "react-native"; 4 | 5 | export default class SearchableSectionList extends Component { 6 | static propTypes = { 7 | sections: PropTypes.array.isRequired, 8 | searchTerm: PropTypes.string.isRequired, 9 | searchAttribute: PropTypes.string.isRequired, 10 | searchByTitle: PropTypes.bool, 11 | ignoreCase: PropTypes.bool 12 | }; 13 | 14 | static defaultProps = { 15 | searchAttribute: "", 16 | searchByTitle: false, 17 | ignoreCase: true 18 | }; 19 | 20 | render() { 21 | const { 22 | sections, 23 | searchAttribute, 24 | searchTerm, 25 | ignoreCase, 26 | searchByTitle 27 | } = this.props; 28 | return ( 29 | { 32 | const { title, data } = sectionData; 33 | const filteredData = data.filter(item => { 34 | let searchDataItem = title; 35 | if (!searchByTitle) { 36 | searchDataItem = searchAttribute 37 | ? searchAttribute 38 | .split(".") 39 | .reduce((prevVal, currVal) => prevVal[currVal], item) 40 | : item; 41 | } 42 | if (ignoreCase) { 43 | return searchDataItem 44 | .toLowerCase() 45 | .includes(searchTerm.toLowerCase()); 46 | } else { 47 | return searchDataItem.includes(searchTerm); 48 | } 49 | }); 50 | 51 | if (filteredData.length !== 0) { 52 | result.push({ 53 | title, 54 | data: filteredData 55 | }); 56 | } 57 | 58 | return result; 59 | }, [])} 60 | /> 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import SearchableFlatList from "./SearchableFlatList"; 2 | import SearchableSectionList from "./SearchableSectionList"; 3 | 4 | export { SearchableFlatList, SearchableSectionList } --------------------------------------------------------------------------------