Skip to content

Instantly share code, notes, and snippets.

@shawnbot
Last active May 25, 2018 16:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shawnbot/d05cfd1b512bf7c86bb3f7363505f615 to your computer and use it in GitHub Desktop.
Save shawnbot/d05cfd1b512bf7c86bb3f7363505f615 to your computer and use it in GitHub Desktop.
A pattern for React components that can change their output element
import React from 'react'
const pass = props => props
export default function chameleon(defaultTag, mapProps = pass) {
const Component = ({tag: Tag = defaultTag, ...rest}) => <Tag {...mapProps(rest)} />
Component.as = tag => chameleon(tag, mapProps || pass)
// if we don't want these to be infinitely as()-able, we could do this instead:
// Component.as = Tag => ({tag, ...rest}) => <Tag {...mapProps(rest)} />
return Component
}
const Text = chameleon('span', ({size}) => ({className: `text-${size}`}))
const Para = Text.as('p')
const Blockquote = Para.as('blockquote')
@shawnbot
Copy link
Author

I'm waffling a bit on the terminology. The word "as" seems more, erm, lyrical than "tag"; but "tag" is way more explicit.

const Para = Text.withTag('b')
<Text tag='b' size='small'>hi</Text>

// vs.
const Para = Text.as('p')
<Text as='b' size='small'>hi</Text>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment