{"id":21018955,"url":"https://github.com/reactabular/selectabular","last_synced_at":"2025-08-02T21:15:25.922Z","repository":{"id":65412231,"uuid":"71750059","full_name":"reactabular/selectabular","owner":"reactabular","description":"Selection utilities (MIT)","archived":false,"fork":false,"pushed_at":"2017-10-02T13:27:35.000Z","size":67,"stargazers_count":3,"open_issues_count":4,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-23T18:05:54.753Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/selectabular","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/reactabular.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-10-24T03:53:08.000Z","updated_at":"2016-11-24T14:09:45.000Z","dependencies_parsed_at":"2023-01-23T10:55:03.851Z","dependency_job_id":null,"html_url":"https://github.com/reactabular/selectabular","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/reactabular/selectabular","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactabular%2Fselectabular","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactabular%2Fselectabular/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactabular%2Fselectabular/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactabular%2Fselectabular/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reactabular","download_url":"https://codeload.github.com/reactabular/selectabular/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reactabular%2Fselectabular/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267103830,"owners_count":24036555,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-26T02:00:08.937Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-19T10:28:20.127Z","updated_at":"2025-08-02T21:15:25.868Z","avatar_url":"https://github.com/reactabular.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![build status](https://secure.travis-ci.org/reactabular/selectabular.svg)](http://travis-ci.org/reactabular/selectabular) [![bitHound Score](https://www.bithound.io/github/reactabular/selectabular/badges/score.svg)](https://www.bithound.io/github/reactabular/selectabular) [![codecov](https://codecov.io/gh/reactabular/selectabular/branch/master/graph/badge.svg)](https://codecov.io/gh/reactabular/selectabular)\n\n# Selectabular - Selection utilities\n\nCommon functionalities when dealing with table rows.\n- (De)-Selecting\n- Filtering\n- Toggling\n\n## API\n\n```javascript\nimport * as select from 'selectabular';\n\n// Or you can cherry-pick\nimport { all } from 'selectabular';\nimport { all as selectAll } from 'selectabular';\n```\n\n### `select.all(rows) =\u003e [\u003crow\u003e]`\n\n- Returned `rows` is an array where each row has a `.selected=true` attribute\n\n### `select.none(rows) =\u003e [\u003crow\u003e]`\n\n- Returned `rows` is an array where each row has a `.selected=false` attribute\n\n### `select.rows(filter)(rows) =\u003e { rows: [\u003crow\u003e], selectedRows: [\u003cmatchingRow\u003e]}`\n\nGiven a filter, it will select the matching rows and return them:\n\n```javascript\nconst initRows = [\n  { id: 10, selected: true, product: 'apple', company: 'Apple Inc', price: 1.5, stock: 300 },\n  { id: 11, product: 'pear', company: 'Pear Inc', price: 3, stock: 1000 },\n  { id: 12, product: 'grape', company: 'Grapesoft', price: 22.1, stock: 18 },\n  { id: 13, product: 'banana', company: 'Banana Tech', price: 12, stock: 9 }\n];\nconst myfilter = row =\u003e row.price \u003e 5\nconst {rows, selectedRows: result } = selectabular.rows(myfilter)(initRows);\n\u003e\u003e result\n[\n  { id: 12,  product: 'grape', company: 'Grapesoft', price: 22.1, stock: 18 },\n  { id: 13,  product: 'banana', company: 'Banana Tech', price: 12, stock: 9 }\n];\n\u003e\u003e rows\n[\n  { id: 10, selected: true, product: 'apple', company: 'Apple Inc', price: 1.5, stock: 300 },\n  { id: 11, product: 'pear', company: 'Pear Inc', price: 3, stock: 1000 },\n  { id: 12, selected: true, product: 'grape', company: 'Grapesoft', price: 22.1, stock: 18 },\n  { id: 13, selected: true, product: 'banana', company: 'Banana Tech', price: 12, stock: 9 }\n];\n```\n\n**Important!**\n\n- `rows` does *not* toggle the rows that do not match the filter; please use `select.none` a priori for that.\n- As shown in the example, `rows`, and `selectedRows` are internal variable names, used in the implementation; which can be easily renamed inline (See example where `selectedRows` is renamed to `result`)\n\n### `select.toggle(filter)(rows) =\u003e [\u003crow\u003e]`\n\n- Input rows where each filter-matching row is toggled its `selected` attribute.\n\n```javascript\nconst initRows = [\n  { id: 10, selected: false, product: 'apple', company: 'Apple Inc', price: 1.5, stock: 300 },\n  { id: 11, selected: true, product: 'pear', company: 'Pear Inc', price: 3, stock: 1000 },\n  { id: 12, product: 'grape', company: 'Grapesoft', price: 22.1, stock: 18 },\n  { id: 13, product: 'banana', company: 'Banana Tech', price: 12, stock: 9 }\n];\nconst filter = row =\u003e row.id \u003c 12\nconst result = selectabular.toggle(filter)(initRows);\n \u003e\u003e result\n[\n  { id: 10, selected: true, product: 'apple', company: 'Apple Inc', price: 1.5, stock: 300 },\n  { id: 11, selected: false, product: 'pear', company: 'Pear Inc', price: 3, stock: 1000 },\n  { id: 12, product: 'grape', company: 'Grapesoft', price: 22.1, stock: 18 },\n  { id: 13, product: 'banana', company: 'Banana Tech', price: 12, stock: 9 }\n];\n```\n\n## React Helpers\n\n### Selecting by Arrow Keys\n\nThere's a single React specific helper that makes it easier to track up/down arrows. The API consists of a single higher order function: `select.byArrowKeys({ rows: \u003crows\u003e, selectedRowIndex: \u003cnumber\u003e, onSelectRow: (selectedRowIndex) =\u003e \u003cany\u003e})(\u003cReact element\u003e) =\u003e \u003cReact element\u003e`\n\nIf there is a selection (`selectedRowIndex`), then it triggers `onSelectRow` with the new `selectedRowIndex` which you can then use to update your selection state.\n\n### How to Use?\n\nThe following example illustrates how to use the functionality with a Reactabular based table. Selection is tracked per row to comply with Reactabular's strict `shouldComponentUpdate`. This allows it to tell apart the rows that have changed while maintaining good performance.\n\nYou can select a row by clicking in the following example. If there's a selection, you can move up and down using the arrow keys.\n\n```jsx\n/*\nimport React from 'react';\nimport classnames from 'classnames';\nimport cloneDeep from 'lodash/cloneDeep';\nimport find from 'lodash/find';\nimport findIndex from 'lodash/findIndex';\nimport { compose } from 'redux';\nimport * as Table from 'reactabular-table';\nimport * as select from 'selectabular';\n*/\n\nconst rows = [\n  {\n    id: 100,\n    name: 'Adam',\n    age: 55\n  },\n  {\n    id: 102,\n    name: 'Joe',\n    age: 12\n  },\n  {\n    id: 101,\n    name: 'Brian',\n    age: 62\n  },\n  {\n    id: 103,\n    name: 'Mike',\n    age: 22\n  },\n  {\n    id: 104,\n    name: 'Jack',\n    age: 33\n  }\n];\n\nconst columns = [\n  {\n    property: 'name',\n    header: {\n      label: 'Name'\n    }\n  },\n  {\n    property: 'age',\n    header: {\n      label: 'Age'\n    }\n  }\n];\n\nclass SelectionTable extends React.Component {\n  constructor(props) {\n    super(props);\n\n    this.state = {\n      rows,\n      columns,\n      selectedRows: []\n    };\n\n    this.onRow = this.onRow.bind(this);\n    this.onSelectRow = this.onSelectRow.bind(this);\n    this.getSelectedRowIndex = this.getSelectedRowIndex.bind(this);\n  }\n  render() {\n    const { columns, rows, selectedRows } = this.state;\n    const selectedRowIndex = this.getSelectedRowIndex(selectedRows);\n\n    return select.byArrowKeys({\n      rows,\n      selectedRowIndex,\n      onSelectRow: this.onSelectRow\n    })(\n      \u003cdiv\u003e\n        \u003cTable.Provider\n          className=\"pure-table pure-table-striped\"\n          columns={columns}\n        \u003e\n          \u003cTable.Header /\u003e\n\n          \u003cTable.Body\n            rows={rows}\n            rowKey=\"id\"\n            onRow={this.onRow}\n          /\u003e\n\n          \u003ctfoot\u003e\n            \u003ctr\u003e\n              \u003ctd\u003eSelected: {selectedRows[0] \u0026\u0026 selectedRows[0].name}\u003c/td\u003e\n              \u003ctd\u003e\u003c/td\u003e\n            \u003c/tr\u003e\n          \u003c/tfoot\u003e\n        \u003c/Table.Provider\u003e\n      \u003c/div\u003e\n    );\n  }\n  onRow(row, { rowIndex }) {\n    return {\n      className: classnames(\n        rowIndex % 2 ? 'odd-row' : 'even-row',\n        row.selected \u0026\u0026 'selected-row'\n      ),\n      onClick: () =\u003e this.onSelectRow(rowIndex)\n    };\n  }\n  onSelectRow(selectedRowIndex) {\n    const { rows } = this.state;\n    const selectedRowId = rows[selectedRowIndex].id;\n\n    this.setState(\n      compose(\n        select.rows(row =\u003e row.id === selectedRowId),\n        select.none\n      )(rows)\n    );\n  }\n  getSelectedRowIndex(selectedRows) {\n    return findIndex(this.state.rows, {\n      id: selectedRows[0] \u0026\u0026 selectedRows[0].id\n    });\n  }\n}\n\n\u003cSelectionTable /\u003e\n```\n\n## License\n\nMIT. See LICENSE for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactabular%2Fselectabular","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freactabular%2Fselectabular","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freactabular%2Fselectabular/lists"}