The Vibration API lets a page request short pulses of tactile feedback from supported devices. Implement a React hook that detects navigator.vibrate after mount and exposes stable functions for starting or cancelling a pattern. The functions must remain safe when the API is absent or changes during the hook's lifetime.
type VibratePattern = number | number[];
function useVibrate(): {
isSupported: boolean;
vibrate: (pattern: VibratePattern) => boolean;
cancel: () => boolean;
};
const { isSupported, vibrate } = useVibrate();
// Call from a user interaction such as a click.
vibrate(120); // forwards 120 to navigator.vibrate
const { vibrate, cancel } = useVibrate();
vibrate([80, 40, 160]); // vibrate, pause, vibrate
cancel(); // forwards 0 to navigator.vibrate
isSupported at false, then detect whether navigator.vibrate is a function in an effect. This keeps the first render safe outside a browser.navigator.vibrate again whenever vibrate or cancel is called. If it is missing, return false without throwing.cancel must call navigator.vibrate(0) and return the boolean value of that call.This hook provides a small, stable React wrapper around an optional browser capability.
A mobile interface may use a short pulse to acknowledge a successful action. The page cannot assume every browser has vibration support, and an accepted request does not prove that physical hardware moved. Your hook must expose the platform's result without inventing extra state.
Treat support detection and each command as separate checkpoints. The effect updates the displayed capability after mount, while every action checks the live API again before it calls.
function useVibrate() {
const isSupported = typeof navigator.vibrate === 'function';
const vibrate = (pattern) => navigator.vibrate(pattern);
const cancel = () => navigator.vibrate(0);
return { isSupported, vibrate, cancel };
}
This reads navigator during render, so rendering outside a browser can throw. It also creates new function objects on every render and calls a method that may disappear. A saved isSupported value is useful for rendering controls, but it is not a safe authorization for a later command.
const { useCallback, useEffect, useState } = require('react');
function browserSupportsVibration() {
return (
typeof navigator !== 'undefined' &&
typeof navigator.vibrate === 'function'
);
}
function useVibrate() {
const [isSupported, setIsSupported] = useState(false);
useEffect(() => {
setIsSupported(browserSupportsVibration());
}, []);
const vibrate = useCallback((pattern) => {
// Capability can change after mount, so guard the actual call too.
if (!browserSupportsVibration()) return false;
return Boolean(navigator.vibrate(pattern));
}, []);
const cancel = useCallback(() => {
if (!browserSupportsVibration()) return false;
return Boolean(navigator.vibrate(0));
}, []);
return { isSupported, vibrate, cancel };
}
module.exports = { useVibrate };
browserSupportsVibration guards both the global object and the current property. The state begins with the same safe answer in every rendering environment, then the effect reconciles it in the browser. useCallback keeps each action's identity stable, while its empty dependency list is safe because the action reads navigator.vibrate only when invoked.
Suppose a button calls vibrate([80, 40, 160]). The callback first confirms that the current navigator.vibrate property is a function. It passes the same array object to the browser, which interprets it as 80 ms of vibration, a 40 ms pause, and 160 ms of vibration. If the browser returns true, your callback returns true; it does not claim that hardware or system settings allowed a physical pulse.
Calling cancel() later forwards 0. The platform stops the current pattern, and a newly accepted non-zero pattern would also replace one already in progress.
vibrate from a click, key, or another user-initiated path.true as proof of motion — limited browser support, missing hardware, Silent mode, Do Not Disturb, or user settings can prevent feedback even after a request is accepted.cancel and let product behavior decide when to call it.success or warning above vibrate, while keeping this wrapper policy-free.AbortSignal in a higher-level sequence helper if your product schedules repeated feedback; this hook intentionally creates no timers.Keep practising the same patterns with a nearby challenge.
No submissions yet
Share your approach and start the discussion.
The Vibration API lets a page request short pulses of tactile feedback from supported devices. Implement a React hook that detects navigator.vibrate after mount and exposes stable functions for starting or cancelling a pattern. The functions must remain safe when the API is absent or changes during the hook's lifetime.
type VibratePattern = number | number[];
function useVibrate(): {
isSupported: boolean;
vibrate: (pattern: VibratePattern) => boolean;
cancel: () => boolean;
};
const { isSupported, vibrate } = useVibrate();
// Call from a user interaction such as a click.
vibrate(120); // forwards 120 to navigator.vibrate
const { vibrate, cancel } = useVibrate();
vibrate([80, 40, 160]); // vibrate, pause, vibrate
cancel(); // forwards 0 to navigator.vibrate
isSupported at false, then detect whether navigator.vibrate is a function in an effect. This keeps the first render safe outside a browser.navigator.vibrate again whenever vibrate or cancel is called. If it is missing, return false without throwing.cancel must call navigator.vibrate(0) and return the boolean value of that call.This hook provides a small, stable React wrapper around an optional browser capability.
A mobile interface may use a short pulse to acknowledge a successful action. The page cannot assume every browser has vibration support, and an accepted request does not prove that physical hardware moved. Your hook must expose the platform's result without inventing extra state.
Treat support detection and each command as separate checkpoints. The effect updates the displayed capability after mount, while every action checks the live API again before it calls.
function useVibrate() {
const isSupported = typeof navigator.vibrate === 'function';
const vibrate = (pattern) => navigator.vibrate(pattern);
const cancel = () => navigator.vibrate(0);
return { isSupported, vibrate, cancel };
}
This reads navigator during render, so rendering outside a browser can throw. It also creates new function objects on every render and calls a method that may disappear. A saved isSupported value is useful for rendering controls, but it is not a safe authorization for a later command.
const { useCallback, useEffect, useState } = require('react');
function browserSupportsVibration() {
return (
typeof navigator !== 'undefined' &&
typeof navigator.vibrate === 'function'
);
}
function useVibrate() {
const [isSupported, setIsSupported] = useState(false);
useEffect(() => {
setIsSupported(browserSupportsVibration());
}, []);
const vibrate = useCallback((pattern) => {
// Capability can change after mount, so guard the actual call too.
if (!browserSupportsVibration()) return false;
return Boolean(navigator.vibrate(pattern));
}, []);
const cancel = useCallback(() => {
if (!browserSupportsVibration()) return false;
return Boolean(navigator.vibrate(0));
}, []);
return { isSupported, vibrate, cancel };
}
module.exports = { useVibrate };
browserSupportsVibration guards both the global object and the current property. The state begins with the same safe answer in every rendering environment, then the effect reconciles it in the browser. useCallback keeps each action's identity stable, while its empty dependency list is safe because the action reads navigator.vibrate only when invoked.
Suppose a button calls vibrate([80, 40, 160]). The callback first confirms that the current navigator.vibrate property is a function. It passes the same array object to the browser, which interprets it as 80 ms of vibration, a 40 ms pause, and 160 ms of vibration. If the browser returns true, your callback returns true; it does not claim that hardware or system settings allowed a physical pulse.
Calling cancel() later forwards 0. The platform stops the current pattern, and a newly accepted non-zero pattern would also replace one already in progress.
vibrate from a click, key, or another user-initiated path.true as proof of motion — limited browser support, missing hardware, Silent mode, Do Not Disturb, or user settings can prevent feedback even after a request is accepted.cancel and let product behavior decide when to call it.success or warning above vibrate, while keeping this wrapper policy-free.AbortSignal in a higher-level sequence helper if your product schedules repeated feedback; this hook intentionally creates no timers.Keep practising the same patterns with a nearby challenge.
No submissions yet
Share your approach and start the discussion.