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

@parhelia/react

v1.0.12951

Published

The React bindings of @parhelia/head for a React rendering head on any framework: the editing bridge (ParheliaBridge after hydration, ParheliaBridgeScript on the server), ParheliaSlot for empty slots and the in-place refresh hook (useParheliaRefresh). Nex

Readme

@parhelia/react

The React bindings of @parhelia/head, for a React rendering head on any framework: Next.js (through @parhelia/next), TanStack Start, React Router, plain Vite SSR. Plain JavaScript, no build step.

| Export | What it is for | |---|---| | ParheliaBridge | loads the editing bridge after hydration when the editor frames the head directly | | ParheliaBridgeScript | renders the bridge's <script> on the server, on the editor's requests | | ParheliaSlot | marks a slot for the editor, also when it is empty | | useParheliaRefresh | the in-place refresh as a hook | | ParheliaPicture | an image cropped by the browser, marked for the editor's cropper |

Everything else a head needs is @parhelia/head's: the server check (@parhelia/head/server), the rendered identity, rich text, a CMS's markers, the build values and the Vite adapter (@parhelia/head/vite). The constants these components' props refer to (PARHELIA_BRIDGE_PATH, EMPTY_SLOT_ATTRIBUTE, the bridge's helpers) are re-exported here.

The editing bridge: ParheliaBridge or ParheliaBridgeScript

A head the editor frames directly (its own URL, another origin than the editor's) loads Parhelia's editing bridge itself: a cross-origin frame cannot be given the bridge by its parent. Below Parhelia's rendering proxy the editor injects it, and neither component is needed. One implementation, two ways to load it:

  • ParheliaBridge, a client component: adds the script after hydration, only in a frame of another origin on ?parhelia=1. It needs no request, and the bridge never touches markup React is still hydrating.

    <ParheliaBridge />
  • ParheliaBridgeScript: renders the <script> where it is rendered, so it is in the server's HTML. Use it where the head's server knows the request and wants the script in the HTML: a CSP nonce, integrity. It renders on every request with ?parhelia=1, whatever frames the page (a server cannot see that); in a same-origin frame the editor then injects nothing. Server components can import it (no "use client").

    // App Router page or layout: the page's searchParams, the response's nonce
    <ParheliaBridgeScript searchParams={await searchParams} nonce={nonce} />
    // a fetch handler or route: the request URL; or decide yourself with `enabled`
    <ParheliaBridgeScript requestUrl={request.url} />

Both load the bridge from /parhelia/editor-bridge/v1/parhelia-bridge.js on the Parhelia origin (origin, default parheliaOrigin()) and name that origin as the bridge's parent (data-parhelia-parent-origin): an HTTPS editor framing an HTTP head sends no referrer to derive the parent from. When another origin serves the bridge (a CMS authoring host that proxies Parhelia's routes), pass it as bridgeOrigin (environment fallback PARHELIA_BRIDGE_ORIGIN, then NEXT_PUBLIC_PARHELIA_BRIDGE_ORIGIN): it only serves the script and is never named as the parent. Both take nonce, integrity, crossOrigin, referrerPolicy and id. The origins come from trusted configuration, never from the query string or a parent-window message; allow the origin that serves the script in the head's CSP script-src.

shouldRenderParheliaBridgeScript({ searchParams | requestUrl }) is the request check alone (for a non-React render), and parheliaBridgeScriptProps(options) the script's attributes. @parhelia/editor-bridge-react, which had ParheliaBridgeScript before, is a deprecated re-export of it.

Empty slots: ParheliaSlot

A Live Preview site tags its fields only, and an empty slot (a reference-array field such as a page's topSection) renders no field: the editor knows the slot from the page's store but not where it is on the page, so the canvas offers no drop zone for it. Wrap each slot's rendering; in Parhelia's frames it renders the slot's markers around it and, when the slot is empty, an empty block (emptyMinHeight, default 6rem) where the editor draws the drop zone; in the editor's preview, which draws no drop zones, the bridge collapses that block. The blocks inside are still found by their own tags. Outside Parhelia's frames it renders the children alone.

import { isParheliaFrameRequest } from '@parhelia/head';
import { ParheliaSlot } from '@parhelia/react';

const inParhelia = isParheliaFrameRequest(useRouter().query);

<ParheliaSlot name="topSection" enabled={inParhelia}>
  {topSection?.map((entry) => <ComponentResolver key={entry.sys.id} componentProps={entry} />)}
</ParheliaSlot>;

name is the slot's key as Parhelia names it: the field's API id for a slot of the page being edited. description (the label, default name) is optional.

In-place refresh: useParheliaRefresh

The editor calls window.requestRefresh(newUri?) after a save. Mount the hook in Parhelia's editing frames with how the head reads the page again and a stable string of what it rendered; it reads again once a second until that string changed and settled, or the deadline passed:

// Next.js Pages Router: getServerSideProps runs again (a fresh query); App Router: router.refresh();
// TanStack Router: router.invalidate()
useParheliaRefresh({ signature: JSON.stringify(pageProps.page), refetch: () => router.replace(withFreshQuery(), undefined, { scroll: false }) });

A head that runs another React than the one this package resolves (linked from a checkout) calls installParheliaRefresh({ refetch, signature: () => latest, deadlineMs }) from @parhelia/head/refresh in its own effect: it imports no React, and its answer removes the hook again.

Cropped pictures: ParheliaPicture

Renders what contentfulPictureSources (@parhelia/head/contentful) computed: the picture's CSS in a <style>, a clipping box of the crop's shape, and a <picture> whose sources and image carry their variant (data-variant) and the crop they apply (data-parhelia-crop). Put the field's annotations on the box (boxProps), so the editor measures the visible box:

import { contentfulPictureSources } from '@parhelia/head/contentful';
import { ParheliaPicture } from '@parhelia/react';

<ParheliaPicture picture={contentfulPictureSources(asset, crops, variants)} alt={asset.description} boxProps={fieldTags} />;

A head that runs another React than the one this package resolves renders the same data with its own elements.