{"id":28995108,"url":"https://github.com/axiscommunications/react-hooks-shareable","last_synced_at":"2025-06-25T04:06:35.157Z","repository":{"id":39863204,"uuid":"290464348","full_name":"AxisCommunications/react-hooks-shareable","owner":"AxisCommunications","description":"React hooks that are  re-used across different projects.","archived":false,"fork":false,"pushed_at":"2022-10-17T12:27:31.000Z","size":408863,"stargazers_count":8,"open_issues_count":2,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-24T06:46:03.930Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/AxisCommunications.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null}},"created_at":"2020-08-26T10:18:47.000Z","updated_at":"2023-09-15T05:46:34.000Z","dependencies_parsed_at":"2022-07-18T17:00:44.934Z","dependency_job_id":null,"html_url":"https://github.com/AxisCommunications/react-hooks-shareable","commit_stats":null,"previous_names":[],"tags_count":59,"template":false,"template_full_name":null,"purl":"pkg:github/AxisCommunications/react-hooks-shareable","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxisCommunications%2Freact-hooks-shareable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxisCommunications%2Freact-hooks-shareable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxisCommunications%2Freact-hooks-shareable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxisCommunications%2Freact-hooks-shareable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AxisCommunications","download_url":"https://codeload.github.com/AxisCommunications/react-hooks-shareable/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AxisCommunications%2Freact-hooks-shareable/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261801988,"owners_count":23211664,"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","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":"2025-06-25T04:06:33.651Z","updated_at":"2025-06-25T04:06:35.125Z","avatar_url":"https://github.com/AxisCommunications.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-hooks-shareable\n\nReact hooks\n\nThis repository provides an explicit list of useful React hooks so you can re-use them across different projects.\nThe hooks that are provided in this repository are used by multiple projects\n\nIf you want to add a React hook or change an existing one, please create an issue or pull request.\n\n## Install\n\n```bash\nyarn add -D react react-hooks-shareable\n```\n\n## Usage\n\n\u003cdetails\u003e\n  \u003csummary\u003euseAnalytics\u003c/summary\u003e\n\nA hook to expose convenience methods for sending page views or events to Google Analytics.\n\nNote: You will still need to set up Google Analytics in your project manually, IE adding the script tag and initialize it and make sure gtag is available on the window object. You also need to have @types/gtag.js as devDependency in your project\n\n```tsx\nimport { useEffect, useCallback } from 'react'\nimport { useAnalytics } from 'react-hooks-shareable'\nimport { Button } from 'someComponentLibrary'\n\nconst GoogleID = 'UA-00000000'\n\nconst MyComponent = () =\u003e {\n  const { pageView, event } = useAnalytics(GoogleID)\n\n  useEffect(() =\u003e {\n    pageView({ page_path: '/myPage' })\n  }, [pageView])\n\n  const onClick = useCallback(() =\u003e {\n    // A simple event\n    event('Create', {\n      event_category: 'EventCategory',\n      event_label: 'Success',\n      value: 10,\n    })\n    // An exception event\n    event('exception', {\n      description: 'Script error on line 32 in main.js',\n      fatal: true, // set to true if the error is fatal\n    })\n  }, [event])\n\n  return \u003cButton label=\"Click me\" onClick={onClick} /\u003e\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseBoolean\u003c/summary\u003e\n\nA hook for easy handling of boolean values. It exposes up to four values and functions in the returned array.\n\n```tsx\nconst [currentValue, setTrue, setFalse, toggleValue] = useBoolean(initialValue)\n```\n\n```tsx\nimport { useBoolean } from 'react-hooks-shareable'\nimport { ConfirmDialog } from 'someComponentLibrary'\n\nconst MyComponent = () =\u003e {\n  const [isOpen, open, close, toggle] = useBoolean(false)\n\n  return (\n    \u003cConfirmDialog\n      open={isOpen}\n      onClose={close}\n      title=\"Dialog\"\n      message=\"Are you sure?\"\n      confirmAction={{\n        label: 'OK',\n        onClick: close,\n      }}\n      cancelAction={{\n        label: 'Cancel',\n        onClick: close,\n      }}\n    /\u003e\n  )\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseClickOutside\u003c/summary\u003e\n\nA hook that fires a callback when a click (pointerdown) was registered outside of a component. Outside is defined as outside of your react tree, which means that this works with portals.\n\n```tsx\nimport { useDraggable } from 'react-hooks-shareable'\n\nconst MyComponent = () =\u003e {\n  const handler = useClickOutside(e =\u003e {\n    console.log('Clicked outside!')\n  })\n\n  return (\n    \u003cdiv onPointerDown={handler}\u003e\n      \u003cspan\u003eClicks here is inside\u003c/span\u003e\n      {ReactDOM.createPortal(\n        \u003cspan\u003eClicks here are also inside\u003c/span\u003e,\n        portalContainer\n      )}\n    \u003c/div\u003e\n  )\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseDeferredTrigger\u003c/summary\u003e\n\nA hook for debouncing a changing boolean value, with different delays depending on the direction of the trigger (determined by the base value).\n\nNote: the trailing delay takes into account the time already spent in the \"on\" state of the trigger.\n\nMainly useful for loading states where one wants to guarantee a period without spinner (delay triggering the loading state), but then when it's loading, make sure the spinner is shown for a minimum amount of time (trailing delay of the trigger).\n\nDefault values:\n\ndelay - 100ms\nminDuration - 400ms\n\n```tsx\nimport { useDeferredTrigger } from 'react-hooks-shareable'\n\nconst MyComponent = () =\u003e {\n  const initializing =\n    gqlClient === undefined || credentials === undefined || online === undefined\n\n  const waiting = useDeferredTrigger(initializing, {\n    delay: 200,\n    minDuration: 500,\n  })\n\n  if (waiting) {\n    return \u003cSpinner\u003e\n  }\n\n  return \u003cYourComponent /\u003e\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseDraggable\u003c/summary\u003e\n\nA hook that provides a translation vector for an element that is being dragged.\n\n```tsx\nimport { useDraggable } from 'react-hooks-shareable'\n\nconst MyComponent = () =\u003e {\n  const [[tx], onDragStart, dragging] = useDraggable(onDragEnd)\n\n  return (\n    \u003cResizeContainer left={tx}\u003e\n      \u003cResizeHandle onPointerDown={onDragStart} /\u003e\n      \u003cResizeMarker dragging={dragging} /\u003e\n    \u003c/ResizeContainer\u003e\n  )\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseFocusDetection\u003c/summary\u003e\n\nA hook which detects if the browser and your page is in focus.\n\n```tsx\nimport { useFocusDetection } from 'react-hooks-shareable'\n\nconst MyComponent = () =\u003e {\n  const hasFocus = useFocusDetection(1000)\n\n  return \u003cspan\u003e{`User ${hasFocus ? : 'is' : 'is not'} focusing on this page`}\u003c/span\u003e\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseHasOverflow\u003c/summary\u003e\n\nA hook for checking if an element has overflow.\n\n```tsx\nimport { useHasOverflow } from 'react-hooks-shareable'\nimport { SomeComponent } from 'someComponentLibrary'\n\nconst MyComponent = () =\u003e {\n  const { hasOverflow, ref } = useHasOverflow()\n\n  return \u003cSomeComponent ref={ref} hasOverflow={hasOverflow} /\u003e\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseId\u003c/summary\u003e\n\nA hook that returns a unique id.\n\n```tsx\nimport { useId } from 'react-hooks-shareable'\n\nconst MyComponent = () =\u003e {\n  const id = useId('someId')\n\n  return \u003cYourComponent id={id} /\u003e\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseInterval\u003c/summary\u003e\n\nA hook for delaying the execution.\n\n```tsx\nimport { useInterval } from 'react-hooks-shareable'\n\nconst MyComponent = () =\u003e {\n  useInterval(() =\u003e console.log('Run'), 100)\n\n  return \u003cYourComponent /\u003e\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseLocalStorage\u003c/summary\u003e\n\nA hook for accessing from or saving the values to localStorage.\n\n```tsx\nimport { useLocalStorage, getLocalStorage } from 'react-hooks-shareable'\nimport { Switch } from 'someComponentLibrary'\n\n// Without hook\nconst storage = getLocalStorage()\nconst theme: ITheme | null = storage['theme']\n\n// With hook\nconst MyComponent = () =\u003e {\n  const [analytics, setAnalytics] = useLocalStorage\u003cboolean | null\u003e('analytics')\n\n  return (\n    \u003cSwitch\n      label={t('label.shareData')}\n      value={analytics === true}\n      onChange={setAnalytics}\n    /\u003e\n  )\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eusePressed\u003c/summary\u003e\n\nA hook for easy detecting if the component is pressed.\n\n```tsx\nimport { usePressed } from 'react-hooks-shareable'\n\nconst MyComponent = () =\u003e {\n  const ref = React.createRef\u003cHTMLInputElement\u003e()\n  const pressed = usePressed(ref)\n\n  useEffect(() =\u003e {\n    if (pressed) {\n      document.addEventListener('pointermove', posSetter)\n      return () =\u003e document.removeEventListener('pointermove', posSetter)\n    }\n  }, [posSetter, pressed])\n\n  return \u003cYourComponent /\u003e\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseResetScroll\u003c/summary\u003e\n\nA hook for easy resetting the scroll to top of ref.\n\n```tsx\nimport { useResetScroll } from 'react-hooks-shareable'\n\nconst MyComponent = () =\u003e {\n  const tableContentRef = useRef\u003cHTMLDivElement\u003e(null)\n\n  // Scroll to top when scrollKey changes\n  useResetScroll(tableContentRef)\n\n  return \u003cTableContainer ref={tableRef} /\u003e\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseScrollPosition\u003c/summary\u003e\n\nA hook for translating the scroll position for an element into atTop and atBottom boolean values, indicating if the scroll position is at the beginning or end of an element.\n\nTo signal that the onScroll function hasn't computed any position yet, atTop and atBottom can be undefined!\n\n```tsx\nimport { useScrollPosition } from 'react-hooks-shareable'\n\nconst MyComponent = () =\u003e {\n  const { atTop, atBottom, scrollRef } = useScrollPosition()\n\n  return (\n    \u003cScrollContainer\n      topHidden={atTop === false}\n      bottomHidden={atBottom === false}\n      ref={scrollRef}\n    \u003e\n      {children}\n    \u003c/ScrollContainer\u003e\n  )\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseSelection\u003c/summary\u003e\n\nA hook to keep track of the selected items.\n\n```tsx\nimport { useSelection } from 'react-hooks-shareable'\nimport { Table, TableHeader, Typography, Menu } from 'someComponentLibrary'\n\nconst MyComponent = () =\u003e {\n  const [selection, add, remove, reset] = useSelection()\n\n  const onSelect = useCallback(\n    (selected: boolean, id?: string) =\u003e {\n      if (selected) {\n        if (id !== undefined) {\n          add(id)\n        } else {\n          reset(LONG_DEVICE_LIST.map(device =\u003e device.id))\n        }\n      } else {\n        if (id !== undefined) {\n          remove(id)\n        } else {\n          reset([])\n        }\n      }\n    },\n    [add, remove, reset]\n  )\n\n  return (\n    \u003cTable onSelect={onSelect} hasMenu={true}\u003e\n      \u003cTableHeader\n        selected={\n          selection.size !== 0 \u0026\u0026 selection.size === LONG_DEVICE_LIST.length\n        }\n        partial={selection.size \u003e 0 \u0026\u0026 selection.size \u003c LONG_DEVICE_LIST.length}\n        overlay={\n          selection.size === 0 ? undefined : (\n            \u003cdiv\u003e\n              \u003cTypography\u003eActions overlay\u003c/Typography\u003e\n            \u003c/div\u003e\n          )\n        }\n        menu={\n          \u003cMenu\n            align=\"right\"\n            items={MENU_ITEMS.map(({ label, ...item }) =\u003e ({\n              ...item,\n              label,\n              onClick: onClickHandler(label),\n            }))}\n          /\u003e\n        }\n      \u003e\n        {TABLE_HEADER_DATA.map(({ title }, id) =\u003e (\n          \u003cTypography key={id}\u003e{title}\u003c/Typography\u003e\n        ))}\n      \u003c/TableHeader\u003e\n    \u003c/Table\u003e\n  )\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseSynchronizedAnimation\u003c/summary\u003e\n\nA hook for synchronizing web animations. The animations are synchronized to\nthe `document.timeline`. This can for example be used to make spinners\nalways be in sync with another, and over remounts.\n\n```css\n.animation {\n  animation: spin 4s linear infinite;\n}\n\n@keyframes spin {\n  100% {\n    transform: rotate(360deg);\n  }\n}\n```\n\n```tsx\nimport { useSynchronizedAnimation } from 'react-hooks-shareable'\n\nconst MyAnimation = () =\u003e {\n  const ref = useSynchronizedAnimation()\n\n  return \u003cdiv className=\"animation\" ref={ref} /\u003e\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseTrigger\u003c/summary\u003e\n\nA hook implementing a generic event.\n\nThe event can, for example, be used to trigger changes to effects.\n\nThe initial state of the event is undefined, otherwise nothing should be assumed of the event returns a triplet consisting of:\n\n0. an event\n1. a function to trigger the event\n2. a function to reset the event to its initial state\n\n```tsx\nimport { useCallback, useMemo } from 'react'\nimport { useTrigger } from 'react-hooks-shareable'\n\nconst MyComponent = () =\u003e {\n  const [clearEvent, triggerClearEvent] = useTrigger()\n\n  const tabs = useMemo(\n    () =\u003e [\n      {\n        id: 'myId',\n        label: 'myLabel',\n      },\n    ],\n    []\n  )\n\n  const onTabSelected = useCallback(\n    (tab: Tab) =\u003e {\n      triggerClearEvent()\n      setCurrentTab(tab)\n    },\n    [triggerClearEvent]\n  )\n  return (\n    \u003cYourComponent\n      tabs={tabs}\n      onTabSelected={onTabSelected}\n      selectedTab={currentTab}\n      clearEvent={clearEvent}\n    /\u003e\n  )\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseUserActive\u003c/summary\u003e\n\nA hook for listening to activity on an element by the user.\n\n```tsx\nimport { useScrollPosition } from 'react-hooks-shareable'\n\nconst MyComponent = () =\u003e {\n  const ref = React.createRef\u003cHTMLInputElement\u003e()\n  const [userActivity, startUserActive, stopUserActive] = useUserActive(\n    ref,\n    4000\n  )\n\n  return \u003cYourComponent /\u003e\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003euseVisibleFocus\u003c/summary\u003e\n\nA hook for easy handling of component's focus.\n\n```tsx\nimport { useVisibleFocus } from 'react-hooks-shareable'\n\nconst MyComponent = () =\u003e {\n  const { isPointerOn, isPointerOff, determineVisibleFocus, visibleFocus } =\n    useVisibleFocus()\n\n  return (\n    \u003cButton\n      onPointerDown={isPointerOn}\n      onPointerUp={isPointerOff}\n      onFocus={determineVisibleFocus}\n      visibleFocus={visibleFocus}\n    \u003e\n      Content\n    \u003c/Button\u003e\n  )\n}\n```\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faxiscommunications%2Freact-hooks-shareable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faxiscommunications%2Freact-hooks-shareable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faxiscommunications%2Freact-hooks-shareable/lists"}