feathericons/feather · error · Error
`feather.replace()` only works in a browser environment.
Error message
`feather.replace()` only works in a browser environment.
What it means
feather.replace() is a browser-only convenience API: it scans the DOM for elements with a `data-feather` attribute and replaces them with the corresponding SVG markup. It calls `document.querySelectorAll`, which only exists in a browser (or a DOM-emulating environment). The library throws this error immediately when `typeof document === 'undefined'` so you get a clear message instead of an opaque ReferenceError.
Source
Thrown at src/replace.js:13
/* eslint-env browser */
import classnames from 'classnames/dedupe';
import icons from './icons';
/**
* Replace all HTML elements that have a `data-feather` attribute with SVG markup
* corresponding to the element's `data-feather` attribute value.
* @param {Object} attrs
*/
function replace(attrs = {}) {
if (typeof document === 'undefined') {
throw new Error('`feather.replace()` only works in a browser environment.');
}
const elementsToReplace = document.querySelectorAll('[data-feather]');
Array.from(elementsToReplace).forEach(element =>
replaceElement(element, attrs),
);
}
/**
* Replace a single HTML element with SVG markup
* corresponding to the element's `data-feather` attribute value.
* @param {HTMLElement} element
* @param {Object} attrs
*/
function replaceElement(element, attrs = {}) {
const elementAttrs = getAttrs(element);
const name = elementAttrs['data-feather'];View on GitHub (pinned to 3dc050d974)
Solutions
- Call feather.replace() only after the DOM is available, e.g. in a browser entry point or a useEffect/componentDidMount-style hook with a browser check.
- Guard the call: only invoke it when typeof document !== 'undefined'.
- In SSR frameworks, move the call into client-side lifecycle code or a 'use client' / mounted-only block.
- In Jest, set testEnvironment to 'jsdom' if you need to test replace().
- If rendering outside a browser, use the string-returning APIs instead: feather.icons[name].toSvg(attrs) and inject the markup yourself.
Example fix
// before
import feather from 'feather-icons';
feather.replace(); // throws in Node/SSR
// after
import feather from 'feather-icons';
if (typeof document !== 'undefined') {
feather.replace();
} Defensive patterns
Strategy: fallback
Validate before calling
if (typeof document === 'undefined') { /* skip replace, use toSvg strings instead */ } Type guard
const canUseFeatherReplace = (): boolean => typeof document !== 'undefined' && typeof document.querySelectorAll === 'function';
Try / catch
try {
feather.replace();
} catch (e) {
if (e.message.includes('browser environment')) {
// SSR/Node path: render icons via feather.icons[name].toSvg() instead
} else {
throw e;
}
} Prevention
- Only call replace() in client-side lifecycle code (useEffect, mounted hooks)
- Guard with typeof document !== 'undefined' in isomorphic code
- Use jsdom test environment when testing DOM replacement
- Prefer feather.icons[name].toSvg() when you control rendering
When it happens
Trigger: Calling feather.replace() in Node.js (no DOM), in a server-side rendering pass (Next.js/Nuxt/Rails SSR), inside a Web Worker, or in a test runner (Jest node environment) where `document` is not defined.
Common situations: Importing feather-icons in a Node script to pre-render icons; calling replace() in a component's server-side render function; running unit tests with testEnvironment:'node'; using the package in an Electron main process.
Related errors
AI-assisted analysis of feathericons/feather@3dc050d974 (2026-08-30).
Data as JSON: /api/errors/4705529eb0b651ab.
Report an issue: GitHub.