diff --git a/docs/usePermission.md b/docs/usePermission.md
new file mode 100644
index 0000000000..4a6b688e5b
--- /dev/null
+++ b/docs/usePermission.md
@@ -0,0 +1,20 @@
+# `usePermission`
+
+React UI hook that query permission status from the user depends on the specific AP.
+
+
+## Usage
+
+```jsx
+import {usePermission} from 'react-use';
+
+const Demo = () => {
+ const state = usePermission({ name: 'microphone' });
+
+ return (
+
+ {JSON.stringify(state, null, 2)}
+
+ );
+};
+```
diff --git a/src/__stories__/usePermission.story.tsx b/src/__stories__/usePermission.story.tsx
new file mode 100644
index 0000000000..3ff7cf6c9a
--- /dev/null
+++ b/src/__stories__/usePermission.story.tsx
@@ -0,0 +1,14 @@
+import { storiesOf } from '@storybook/react';
+import * as React from 'react';
+import { usePermission } from '..';
+import ShowDocs from './util/ShowDocs';
+
+const Demo = () => {
+ const state = usePermission({ name: 'microphone' });
+
+ return {JSON.stringify(state, null, 2)}
;
+};
+
+storiesOf('UI|usePermission', module)
+ .add('Docs', () => )
+ .add('Demo', () => );
diff --git a/src/index.ts b/src/index.ts
index be432e22d6..69002fa119 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -47,6 +47,7 @@ import useNumber from './useNumber';
import useObservable from './useObservable';
import useOrientation from './useOrientation';
import usePageLeave from './usePageLeave';
+import usePermission from './usePermission';
import usePrevious from './usePrevious';
import usePromise from './usePromise';
import useRaf from './useRaf';
@@ -123,6 +124,7 @@ export {
useObservable,
useOrientation,
usePageLeave,
+ usePermission,
usePrevious,
usePromise,
useRaf,
diff --git a/src/usePermission.ts b/src/usePermission.ts
new file mode 100644
index 0000000000..37b0261031
--- /dev/null
+++ b/src/usePermission.ts
@@ -0,0 +1,46 @@
+import { useEffect, useState } from 'react';
+import { off, on } from './util';
+
+type PermissionDesc =
+ | PermissionDescriptor
+ | DevicePermissionDescriptor
+ | MidiPermissionDescriptor
+ | PushPermissionDescriptor;
+
+const noop = () => {};
+
+const usePermission = (permissionDesc: PermissionDesc): string => {
+ const [state, setState] = useState('');
+ let mounted = true;
+ let permissionStatus: PermissionStatus | null = null;
+
+ const onChange = () => {
+ if (mounted && permissionStatus) {
+ setState(permissionStatus.state);
+ }
+ };
+
+ const changeState = () => {
+ onChange();
+ on(permissionStatus, 'change', onChange);
+ };
+
+ useEffect(() => {
+ navigator.permissions
+ .query(permissionDesc)
+ .then(status => {
+ permissionStatus = status;
+ changeState();
+ })
+ .catch(noop);
+
+ return () => {
+ mounted = false;
+ permissionStatus && off(permissionStatus, 'change', onChange);
+ };
+ }, []);
+
+ return state;
+};
+
+export default usePermission;