npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@cypress-design/favicon

v1.0.0

Published

The Cypress favicon assets and the head markup that declares them.

Readme

@cypress-design/favicon

The Cypress favicon assets and the head markup that declares them.

Most sites should not install this directly. If your <head> is rendered by Astro, install @cypress-design/vue-favicon or @cypress-design/react-favicon instead — each brings this package, its icon files and its copy command with it. Install this package on its own only when your head cannot render a component: a Docusaurus plugin, an EJS template, or other server-rendered HTML. Full documentation: Favicon.

Why this is a file copy, not an import

A favicon never enters the document. The browser fetches it as a standalone URL and paints it into its own chrome — the tab strip, bookmarks, history — usually before the JavaScript bundle exists. So unlike the rest of the design system, this package has to put real files on disk.

Usage

Copy the assets into whatever directory your site serves statically, as a prebuild step:

// package.json
{
  "scripts": {
    "prebuild": "cypress-favicon public", // `static` for Docusaurus
  },
}

Then declare the markup. Which form you use depends on what your head layer accepts — all three come from the same FAVICON_LINKS array, so they cannot disagree with each other.

Astro

---
// use the build matching a framework your Astro config registers
import Favicon from '@cypress-design/vue-favicon'
// or, on a site whose Astro config registers React:
// import Favicon from '@cypress-design/react-favicon'
---
<head>
  <Favicon />
</head>

Picking the wrong one is not merely redundant. Astro finds a renderer by asking each registered one in turn, and @astrojs/react's check throws on a compiled Vue component rather than returning false — so a Vue component on a site that registers React first crashes every page.

Pass links to narrow the list, e.g. for a site that ships no web manifest:

<Favicon links={FAVICON_LINKS.filter((l) => l.rel !== 'manifest')} />

Docusaurus

A Docusaurus plugin injects objects rather than markup, so there is no component to render:

const { faviconHeadTags } = require('@cypress-design/favicon')

module.exports = async function favIcon() {
  return {
    name: 'docusaurus-plugin-favicon',
    injectHtmlTags: () => ({ headTags: faviconHeadTags() }),
  }
}

EJS and other server-rendered HTML

<head>
  <%- faviconLinksHtml() %>
</head>

EJS templates take a string. This is also the only form that works on a page with no JavaScript at all — a server-rendered page with no <script> tags has nothing for a component to mount into.

Why not a component everywhere

The component renders <link> elements, so it needs a framework doing the rendering at the point the <head> is built. Astro does. A Docusaurus plugin hands back descriptors before any component tree exists, and an EJS template has no component runtime. A client-side React component can reach the head after hydration, but a favicon is fetched during the initial HTML parse — so injecting it later means the browser has already asked for /favicon.ico and moved on.

Two things deliberately absent

No rel="icon" entry for favicon.ico, and no rel="mask-icon" at all.

The ICO rule

FAVICON_LINKS deliberately contains no rel="icon" entry for favicon.ico.

Measured against Chrome 153 and Safari 26.5: when an ICO is declared, it beats the SVG in both engines regardless of sizes or document order, and Chrome does not even download the SVG. The widely copied <link rel="icon" href="/favicon.ico" sizes="any"> line is what prevents the adaptive icon from being used, not what enables it.

The ICO is still shipped and still served. Clients that want it — Safari before 26, crawlers, unfurlers, RSS readers — request /favicon.ico from the origin root by convention, without reading your markup. Keep the file at the root and leave it undeclared.

What's in the box

| File | Used by | | ---------------------- | ------------------------------------------------------------------------- | | favicon.svg | Chrome, Edge, Firefox — adapts to light/dark via prefers-color-scheme | | favicon.ico | Safari before 26, crawlers, unfurlers. Real ICO container, 16/24/32/48/64 | | apple-touch-icon.png | iOS home screen. 180×180, no alpha | | android-chrome-*.png | Android and installed PWAs, via the manifest |

The ICO is baked from the dark variant with the navy disc filled. It cannot adapt, so it has to be one image that survives on a light or a dark tab strip — a filled disc gives the wordmark its own background either way.

Safari 26 renders the SVG but always resolves it light, so its dark-mode tab shows the light variant. That is legible, just not identical to Chrome.

Local development

exports points at dist/, so a linked consumer sees built output, not source. Rebuild after editing:

yarn workspace @cypress-design/favicon build

Why there is no mask-icon

Safari required a flat monochrome safari-pinned-tab.svg for pinned tabs from Safari 9 (2015). Safari 12 (2018) started using the regular favicon there instead, and it has never been required since. Verified inert in Safari 26.5: a pinned tab renders the full-colour favicon whether or not the tag is declared. Apple's guidance for it is archived, and apple.com no longer ships it.

Note that Safari renders favicon.svg but always resolves it light, in both appearances — so a Safari dark-mode tab shows the light variant while Chrome and Firefox show the dark one.