Skip to content

request: add as rendering #419

@hairyf

Description

@hairyf

Is there an existing issue or pull request for this?

  • I have searched the existing issues and pull requests

Feature description

Adding a as prop is a very interesting feature. As an advanced abstraction layer, it can determine the type of element to render based on the passed-in as. This is particularly useful in scenarios that require dynamic rendering. For example, we may need to render different elements based on various conditions and add animation effects.

Desired solution

import { AnimatePresence, motion } from 'motion/react';
import { If } from 'react-if';

function List({ loading, list }) {
  const [tag, setTag] = useState('h1');
  return (
    <If condition={!loading} as={AnimatePresence} initial={false}>
      <Then 
        as={motion.div}
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
      >
        {/* ... */}
      </Then>
      <Else
        as={motion.div} 
        initial={{ opacity: 0 }} 
        animate={{ opacity: 1 }} 
        exit={{ opacity: 0 }}
      >
        {/* ... */}
      </Else>
    </If>
  );
}

Corresponding implementation:

import type { JSX } from 'react'
import { createElement } from 'react'

export type WrapperAs = keyof JSX.IntrinsicElements | Function

export type WrapperProps<As extends keyof JSX.IntrinsicElements | React.FC | unknown> =
  { as?: As } &
  (As extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[As] : unknown) &
  (As extends React.FC<infer P> ? P : unknown)

export function wrapper(as: any, props: unknown, children?: React.ReactNode) {
  return as ? createElement(as, props, children) : children
}

// if.tsx
export type IfProps<As> = WrapperProps<As> & {
  condition?: BooleanLike
  children?: ReactNode
}

export function If<As extends WrapperAs>(props: IfProps<As>) {
  const { condition, children, as, ...attrs } = props
  // ...
  return wrapper(as, attrs, content)
}

Alternatives considered

none

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions