All Projects → kripod → React Polymorphic Box

kripod / React Polymorphic Box

Licence: mit
Building blocks for strongly typed polymorphic components in React.

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to React Polymorphic Box

Property Access
The PropertyAccess component provides function to read and write from/to an object or array using a simple string notation.
Stars: ✭ 2,362 (+1046.6%)
Mutual labels:  component
React Popup
React popup component
Stars: ✭ 198 (-3.88%)
Mutual labels:  component
Rdvcalendarview
Highly customizable calendarView and calendarViewController for iOS
Stars: ✭ 203 (-1.46%)
Mutual labels:  component
Inflector
Inflector converts words between their singular and plural forms (English only).
Stars: ✭ 2,232 (+983.5%)
Mutual labels:  component
Silentbox
A lightbox inspired Vue.js component.
Stars: ✭ 196 (-4.85%)
Mutual labels:  component
Expression Language
The ExpressionLanguage component provides an engine that can compile and evaluate expressions.
Stars: ✭ 2,418 (+1073.79%)
Mutual labels:  component
Vuetify Daterange Picker
The missing date range picker for Vuetify JS you have been looking for.
Stars: ✭ 192 (-6.8%)
Mutual labels:  component
Flap
Flap(灵动),一个基于 RecyclerView 的页面组件化框架。
Stars: ✭ 204 (-0.97%)
Mutual labels:  component
React Sticky Table
Responsive and dynamically-sized fixed headers and columns for tables
Stars: ✭ 198 (-3.88%)
Mutual labels:  component
Komponents Deprecated
📦 React-inspired UIKit Components - ⚠️ Deprecated
Stars: ✭ 202 (-1.94%)
Mutual labels:  component
Malagu
Malagu Development Framework (QQ: 1013685855 钉钉群:31992376)
Stars: ✭ 196 (-4.85%)
Mutual labels:  component
Brouter
Stars: ✭ 198 (-3.88%)
Mutual labels:  component
Jsonsubtypes
Discriminated Json Subtypes Converter implementation for .NET
Stars: ✭ 201 (-2.43%)
Mutual labels:  polymorphism
Stopwatch
The Stopwatch component provides a way to profile code.
Stars: ✭ 2,388 (+1059.22%)
Mutual labels:  component
Babel Plugin React Intl Auto
i18n for the component age. Auto management react-intl ID.
Stars: ✭ 203 (-1.46%)
Mutual labels:  component
Component
🔥🔥🔥A powerful componentized framework.一个强大、100% 兼容、支持 AndroidX、支持 Kotlin并且灵活的组件化框架
Stars: ✭ 2,434 (+1081.55%)
Mutual labels:  component
Vue Rate
Rate component for Vue
Stars: ✭ 199 (-3.4%)
Mutual labels:  component
Vue Easytable
🍉 Table Component/ Data Grid / Data Table.Support Virtual Scroll,Column Fixed,Header Fixed,Header Grouping,Filter,Sort,Cell Ellipsis,Row Expand,Row Checkbox ...
Stars: ✭ 2,501 (+1114.08%)
Mutual labels:  component
Navigation Stack
NavigationStack is a stack-modeled UI navigation controller. Swift UI library made by @Ramotion
Stars: ✭ 2,289 (+1011.17%)
Mutual labels:  component
Vue Upload Component
Vue.js file upload component, Multi-file upload, Upload directory, Drag upload, Drag the directory, Upload multiple files at the same time, html4 (IE 9), `PUT` method, Customize the filter
Stars: ✭ 2,422 (+1075.73%)
Mutual labels:  component

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>;
}
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].