Skip to content

attachReactJsxNode convenience feature to help injecting React components in the "faked/compatibility" react JSX #2757

@timurxyz

Description

@timurxyz

What is the feature you are proposing?

#2508

Feature/Rationale

hono/jsx/dom in many cases now allows for interoperation with React UI libraries / components (guests) without actually running / mounting a real React renderer or explicitly wrapping user code in react-renderer middleware. However additional code/method sugar around in-place rendering of such guest React components might help code logic / DX.

Example of usage

We could take a React React component from shadcn or Tamagui or similar like:
https://ui.shadcn.com/docs/components/tooltip
and wrap it into a hono/honox (island) custom component like so (the styling issues are omitted here):

import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger,} 
from '@/components/ui/tooltip'
import { attachReactJsxNode } from 'hono/jsx/dom'

export default function TtDemo (/* props/children in case of a button/etc */) {

  const tt = 
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger>Hover</TooltipTrigger>
        <TooltipContent>
          <p>Add to library</p>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>

  return attachReactJsxNode(tt)  // children are handled in the JSX above
}

// On the higher level then: <><TtDemo /></> OR <MyTamaguiButton children attribs /> ...

(Also works with a simple Tamagui button as of 240520)

Reference implementation code of the idea

import { useEffect } from 'hono/jsx'
import { render } from 'hono/jsx/dom'
// import { v4 as uuidv4 } from 'uuid'
// import { nanoid } from 'nanoid/non-secure';

export function attachReactJsxNode (
  jsxNode: JSX.Element  // shall come from island or an other "browser-time" component (?) *
) {
  const mountPointId = _randomId()   // uuidv4() / nanoid()

  useEffect(() => {
    render(jsxNode, document.getElementById(mountPointId)!)
  }, [])

  return <span id={mountPointId} style={{display:'content'}} />
}

// if no random id lib used, then:
function _randomId () { return Math.random().toString(36).replace(/^0\./, '_') }

Note: Children are handled in the ingress JSX

The above sample implementation code works. The actual implementation might better utilize the hono/useEffect internals or other dom lifecycle related internals.

*Please extend with the SSR/SSG aspects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions