• Stars
    star
    311
  • Rank 134,521 (Top 3 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created almost 5 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Building blocks for strongly typed polymorphic components in React.

react-polymorphic-box

Building blocks for strongly typed polymorphic components in React.

npm Language grade: JavaScript Travis (.com) Commitizen friendly

Animated demonstration of package capabilities

💡 Motivation

Popularized by Styled Components v4, the as prop allows changing the HTML tag rendered by a component, e.g.:

import { Box } from 'react-polymorphic-box';
import { Link } from 'react-router-dom';

<Box as="a" href="https://github.com/kripod">GitHub</Box>
<Box as={Link} to="/about">About</Box>

While this pattern has been encouraged by several libraries, typings had lacked support for polymorphism, missing benefits like:

  • Automatic code completion, based on the value of the as prop
  • Static type checking against the associated component's inferred props
  • HTML element name validation

📚 Usage

A Heading component can demonstrate the effectiveness of polymorphism:

<Heading color="rebeccapurple">Heading</Heading>
<Heading as="h3">Subheading</Heading>

Custom components like the previous one may utilize the package as shown below.

import { Box, PolymorphicComponentProps } from "react-polymorphic-box";

// Component-specific props should be specified separately
export type HeadingOwnProps = {
  color?: string;
};

// Merge own props with others inherited from the underlying element type
export type HeadingProps<
  E extends React.ElementType
> = PolymorphicComponentProps<E, HeadingOwnProps>;

// An HTML tag or a different React component can be rendered by default
const defaultElement = "h2";

export function Heading<E extends React.ElementType = typeof defaultElement>({
  color,
  style,
  ...restProps
}: HeadingProps<E>): JSX.Element {
  // The `as` prop may be overridden by the passed props
  return <Box as={defaultElement} style={{ color, ...style }} {...restProps} />;
}

Typing external components

Alternatively, you can also type your custom components by using the PolymorphicComponent type. This is especially handy when working with external libraries that already expose polymorphic components. Here's an example implementing the Heading component from above using styled-components:

import { PolymorphicComponent } from "react-polymorphic-box";
import styled from "styled-components";

// Component-specific props
export type HeadingProps = {
  color?: string;
};

// An HTML tag or a different React component can be rendered by default
const defaultElement = "h2";

export const Heading: PolymorphicComponent<
  HeadingProps, // Merged with props from the underlying element type
  typeof defaultElement // Default element type (optional, defaults to 'div')
> = styled(defaultElement)<HeadingProps>`
  color: ${(props) => props.color};
`;

Forwarding Refs

Library authors should consider encapsulating reusable components, passing a ref through each of them:

import { Box } from "react-polymorphic-box";

export const Heading: <E extends React.ElementType = typeof defaultElement>(
  props: HeadingProps<E>
) => React.ReactElement | null = React.forwardRef(
  <E extends React.ElementType = typeof defaultElement>(
    { color, style, ...restProps }: HeadingProps<E>,
    ref: typeof restProps.ref
  ) => {
    return (
      <Box
        as={defaultElement}
        ref={ref}
        style={{ color, ...style }}
        {...restProps}
      />
    );
  }
);

The component can then receive a ref prop (live demo), just like a regular HTML element:

import { useRef } from "react";

function App() {
  const ref = useRef<HTMLHeadingElement>(null);
  return <Heading ref={ref}>It works!</Heading>;
}

More Repositories

1

otion

Atomic CSS-in-JS with a featherweight runtime
TypeScript
624
star
2

react-hooks

Essential set of React Hooks for convenient Web API consumption and state management.
TypeScript
553
star
3

glaze

CSS-in-JS microlibrary for making design systems approachable with React
TypeScript
413
star
4

react-polymorphic-types

Zero-runtime polymorphic component definitions for React
169
star
5

uuidv7

UUIDv7 generator with millisecond precision
TypeScript
73
star
6

knex-orm

Knex-based object-relational mapping for JavaScript.
JavaScript
62
star
7

mental-poker

A purely functional mental poker library, based on the thesis of Choongmin Lee.
JavaScript
61
star
8

style-vendorizer

Tiny CSS vendor prefixer and property alias mapper for runtime styling solutions
TypeScript
56
star
9

keez

Frictionless hotkey handling for browsers
TypeScript
55
star
10

gatsby-starter-modern

DEPRECATED. Please use gatsby-starter-strict instead, see the linked website!
JavaScript
55
star
11

gatsby-starter-strict

A Gatsby starter with strict linting and auto-formatting rules.
TypeScript
41
star
12

material-components-react

Modular and customizable Material Design UI components for React.
JavaScript
32
star
13

PoloniexApi.Net

Application Programming Interface for data transmission and retrieval from Poloniex through the Microsoft .NET Framework
C#
32
star
14

css-homogenizer

Base CSS encouraging proper HTML semantics and the use of custom design tokens
CSS
31
star
15

next-starter-strict

A strict Next.js starter with Tailwind CSS, TypeScript, ESLint and Prettier
TypeScript
27
star
16

react-layout-components

Layout components for React, primarily inspired by Every Layout (https://every-layout.dev/)
TypeScript
26
star
17

elgamal.js

ElGamal cryptosystem for JavaScript.
JavaScript
25
star
18

css-shorthand-expanders

Type-safe functions to expand CSS shorthands into their longhand sub-properties
TypeScript
23
star
19

MoneroGui.Net

Provides a GUI to interact with the Monero Core assemblies.
C#
18
star
20

provably-fair

Tools for creating and verifying provably fair games.
JavaScript
16
star
21

wsx

Programmatically extensible lightweight WebSocket implementation in JavaScript.
JavaScript
13
star
22

MoneroApi.Net

API for data transmission and retrieval from Monero applications through the Microsoft .NET Framework
C#
10
star
23

bookshelf-validate

Validation for the Model objects of Bookshelf.js
JavaScript
8
star
24

polonibox

Easily check the legitimacy of Poloniex trollbox users and prove the existence of conversations, avoiding scammers to gain reputation.
PHP
8
star
25

exigo

Responsive Quiz Application made with React and Prisma Framework.
TypeScript
7
star
26

redux-for-beginners

An opinionated set of good practices to minimize the effort required to set up and maintain a Redux project.
JavaScript
6
star
27

provably-fair-algorithms-whitepaper

Introduction to Provably Fair Gaming Algorithms
TeX
5
star
28

react-typed-inputs

Strongly typed input components for React.
TypeScript
5
star
29

record-like-deep-assign

Recursively assigns enumerable own properties of the given sources to a target object
TypeScript
5
star
30

tailwindcss-inner-border

A Tailwind CSS plugin that provides utilities for creating inner borders with box-shadow.
JavaScript
4
star
31

astro-starter-strict

A strict Astro starter with Tailwind CSS, TypeScript, ESLint and Prettier
Astro
3
star
32

chip8-emulator

A CHIP-8 emulator written in JavaScript for educational purposes.
JavaScript
3
star
33

schdesign-web-workshop

Schönherz Design Stúdió frontend workshop
HTML
3
star
34

monero-prices.js

Wrapper for the API methods of moneropric.es, written in JavaScript.
JavaScript
3
star
35

gatsby-plugin-cesium

A Gatsby plugin to add support for CesiumJS
JavaScript
3
star
36

parcel-starter-modern

A modern Parcel starter aiming for high productivity with mostly vanilla techniques.
HTML
2
star
37

deckster

An open-source JavaScript library for creating card games.
JavaScript
2
star
38

express-route-fs

File system-based approach for handling routes in Express.
JavaScript
2
star
39

gatsby-plugin-preval

A Gatsby plugin for pre-evaluating code at build-time
JavaScript
1
star
40

podicons

Handwritten SVG icons with compressibility in mind
1
star
41

hmac-rng.js

HMAC-based random number generator written in JavaScript.
JavaScript
1
star
42

tailwindcss-bug-via-transparent

`via-transparent` utility broken in Safari
JavaScript
1
star
43

pcg.js

A functional implementation of the PCG family random number generators, written in JavaScript.
JavaScript
1
star