Let's create a simple React hook to detect browsers and their capabilities
Dima Vyshniakov
Posted on September 30, 2024
User agent sniffing is the most popular approach for browser detection. Unfortunately, it's not very accessible for a front end development because of multiple reasons. Browser vendors constantly trying to make sniffing not possible. Thus, each browser has their own user agent string format, which is very complex to parse.
There is a much more simple way of achieving the same using browser CSS API, which I'm going to show you. So let's create browser capabilities detection React hook.
We are going to use CSS.supports() static method. It returns a boolean value indicating if the browser supports a given CSS feature, or not. This is javascript analog of @supports at-rule. It works similar to media queries, but with CSS capabilities as a subject.
Hook to detect supported features
The most naive approach of calling CSS.supports()
during component render cycle will create problems in Server Side Rendering environments, such as Next.js. Because the server side renderer has no access to browser APIs, it just produces a string of code.
import type {FC} from 'react';
const Component: FC = () => {
// 🚫 Don't do this!
const hasFeature = CSS.supports('your-css-declaration');
// ...
}
We will use this simple hook instead. The hook receives a string containing support condition, a CSS rule we are going to validate, e.g. display: flex
.
import {useState, useEffect} from 'react';
export const useSupports = (supportCondition: string) => {
// Create a state to store declaration check result
const [checkResult, setCheckResult] = useState<boolean | undefined>();
useEffect(() => {
// Run check as a side effect, on user side only
setCheckResult(CSS.supports(supportCondition));
}, [supportCondition]);
return checkResult;
};
Now we can check for different CSS features support from inside React component.
import type {FC} from 'react';
const Component: FC = () => {
// Check for native `transform-style: preserve` support
const hasNativeTransformSupport = useSupports('
(transform-style: preserve)
');
// Check for vendor prefixed `transform-style: preserve` support
const hasNativeTransformSupport = useSupports('
(-moz-transform-style: preserve) or (-webkit-transform-style: preserve)
');
// ...
}
Detect user browser using CSS support conditions
In order to detect user browser, we have to do a little hacking.
Browser hack has nothing to do with law violations. It's just a special CSS declaration or selector which works differently in one of available browsers.
Here is the reference page with various browser hacks. After thorough experimentation on my machine, I've chosen these:
const hacksMapping = {
// anything -moz will work, I assume
firefox: '-moz-appearance:none',
safari: '-webkit-hyphens:none',
// tough one because Webkit and Blink are relatives
chrome: '
not (-webkit-hyphens:none)) and (not (-moz-appearance:none)) and (list-style-type:"*"'
}
And here is our final hook look like:
export const useDetectBrowser = () => {
const isFirefox = useSupports(hacksMapping.firefox);
const isChrome = useSupports(hacksMapping.chrome);
const isSafari = useSupports(hacksMapping.safari);
return [
{browser: 'firefox', condition: isFirefox},
{browser: 'chromium based', condition: isChrome},
{browser: 'safari', condition: isSafari},
].find(({condition}) => condition)?.browser as
'firefox' | 'chromium based' | 'safari' | undefined;
};
Full demo
Here is a full working demo of the hook.
Final thoughts
While I cannot assert that this method is entirely foolproof or stable, it is important to note that browsers frequently undergo updates, and vendor-specific properties are often deprecated or replaced by standardized ones. This issue is equally applicable to user agent sniffing, as both approaches encounter similar challenges.
However, the CSS.supports()
method offers a more maintainable and granular solution. It encourages developers to adopt strategies such as graceful degradation or progressive enhancement, allowing for more precise and adaptable patch applications.
Happy coding.
Posted on September 30, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
September 30, 2024