--- title: createComponent description: "The `createComponent` function create a component that supports conditional styles such as variants. You can also easily create slot components by using the `createSlotComponent` function." --- ## Overview `createComponent` creates a component that supports conditional styles such as variants. The created component can be inherited, has high extensibility, and generates `className` and `displayName`, so you can also create components with consistent naming conventions in your project. ## Usage To create a single component, use [createComponent](#createcomponent), and to create a slot component, use [createSlotComponent](#createslotcomponent). ### createComponent To create a single component, use `createComponent`. ```tsx import type { HTMLStyledProps, ThemeProps } from "@yamada-ui/react" import { createComponent, defineComponentStyle } from "@yamada-ui/react" ``` ```tsx import type { HTMLStyledProps, ThemeProps } from "@/components/ui" import { createComponent, defineComponentStyle } from "@/components/ui" ``` ```tsx import type { HTMLStyledProps, ThemeProps } from "@workspaces/ui" import { createComponent, defineComponentStyle } from "@workspaces/ui" ``` ```tsx const componentStyle = defineComponentStyle({ base: { /* base style */ }, variants: { /* variant style */ }, sizes: { /* size style */ }, props: { /* props style */ }, compounds: { /* compound style */ }, defaultProps: { /* default props */ }, }) type ComponentStyle = typeof componentStyle export interface ComponentProps extends HTMLStyledProps<"div">, ThemeProps {} const { component, ComponentContext, PropsContext: ComponentPropsContext, useComponentContext, usePropsContext: useComponentPropsContext, withContext, useComponentProps, } = createComponent("component", componentStyle) export { ComponentPropsContext, useComponentPropsContext } ``` :::note `defineComponentStyle` is a function that defines the component style. This function has an important role in type completion. ::: - The first argument is the component name used for `className` and `displayName`. - The second argument is the component style. #### Create a component To create a component, use `withContext`. Set the argument to the HTML element name or function. `withContext` uses the provided style and `PropsContext` props. ```tsx export const Component = withContext("div")() ``` ```tsx export const Component = withContext((props) => { return })() ``` If you don't want to use the provided style and `PropsContext` props, or want to handle the logic, use `component`. ```tsx export const Component = component((props) => { const computedProps = useComponentProps(props) return })() ``` #### Calculate props `withContext` and `component` can perform multi-stage calculations on the provided props. ```tsx export const Component = withContext("button")( { "aria-label": "Default Label" }, ({ "aria-label": ariaLabel, ...rest }) => ({ ariaLabel: ariaLabel === "Default Label" ? "Changed Label" : ariaLabel, ...rest, }), ) ``` :::warning For objects, they are deeply merged. For functions, you need to return the provided props. If you don't return the provided props, the provided props will be lost. ::: #### Transfer props Style props are filtered after calculating the styling. If you also want to use it in the component logic, use `transferProps`. ```tsx export const Component = withContext( ({ size, ...rest }) => { return }, { transferProps: ["size"], }, )() ``` #### Inherit a component `createComponent` created components can be inherited. ```tsx import { Component } from "./component" ``` ```tsx const additionalComponentStyle = defineComponentStyle({ base: { /* base style */ }, variants: { /* variant style */ }, sizes: { /* size style */ }, props: { /* props style */ }, compounds: { /* compound style */ }, defaultProps: { /* default props */ }, }) type AdditionalComponentStyle = typeof additionalComponentStyle export interface AdditionalComponentProps extends HTMLStyledProps<"div">, ThemeProps {} const { ComponentContext, PropsContext: AdditionalComponentPropsContext, useComponentContext, usePropsContext: useAdditionalComponentPropsContext, useComponentProps, withContext, component, } = createComponent( "additional-component", additionalComponentStyle, ) export { AdditionalComponentPropsContext, useAdditionalComponentPropsContext } ``` ```tsx export const AdditionalComponent = withContext(Component)() ``` This creates an `AdditionalComponent` that inherits `Component`. The difference from the traditional component inheritance is that it can merge [ref](https://ja.react.dev/learn/referencing-values-with-refs), class names, styles, and [event handlers](https://ja.react.dev/learn/responding-to-events). ```tsx export const AdditionalComponent: FC = ({ className, ...rest }) => { const ref = useRef(null) const onClick = useCallback(() => {}, []) return ( ) } ``` In this case, if `ref` and `onClick` exist in the provided props, they will be overwritten. Depending on the logic, it may not work well. To solve this, you need to merge each value and logic for each component. ```tsx export const AdditionalComponent: FC = ({ ref: forwardedRef, className, onClick: onClickProp, ...rest }) => { const ref = useRef(null) const onClick = useCallback(() => {}, []) return ( ) } ``` By using `createComponent` to inherit a component, you can automatically merge event handlers such as `ref` and `onClick`. :::note If there is a style conflict, that is, each component has `variants`, the `variants` of the inherited component will take precedence. ::: ### createSlotComponent To create a slot component, use `createSlotComponent`. The functionality is the same as [createComponent](#createcomponent). ```tsx import type { HTMLStyledProps, ThemeProps } from "@yamada-ui/react" import { createSlotComponent, defineComponentSlotStyle } from "@yamada-ui/react" ``` ```tsx import type { HTMLStyledProps, ThemeProps } from "@/components/ui" import { createSlotComponent, defineComponentSlotStyle } from "@/components/ui" ``` ```tsx import type { HTMLStyledProps, ThemeProps } from "@workspaces/ui" import { createSlotComponent, defineComponentSlotStyle } from "@workspaces/ui" ``` ```tsx const componentStyle = defineComponentSlotStyle({ base: { root: { /* base root style */ }, item: { /* base item style */ }, }, variants: { /* variant style */ }, sizes: { /* size style */ }, props: { /* props style */ }, compounds: { /* compound style */ }, defaultProps: { /* default props */ }, }) type ComponentStyle = typeof componentStyle export interface ComponentRootProps extends HTMLStyledProps<"div">, ThemeProps {} const { ComponentContext, PropsContext: ComponentPropsContext, StyleContext, useComponentContext, usePropsContext: useComponentPropsContext, useStyleContext, useClassNames, useRootComponentProps, useSlotComponentProps, withProvider, withContext, component, } = createSlotComponent( "component", componentStyle, ) export { ComponentPropsContext, useComponentPropsContext } ``` :::note `defineComponentSlotStyle` is a function that defines the component style. This function has an important role in type completion. ::: - The first argument is the component name prefix used for `className` and `displayName`. - The second argument is the component style. #### Create a component To create a component, use `withProvider` and `withContext`. Each sets the argument to the HTML element name or function for the first argument, and the slot name for the second argument. `withProvider` uses the provided style and `PropsContext` props to generate a context. `withContext` uses the context generated by `withProvider` to use the style based on the slot name. ```tsx export const RootComponent = withProvider("div", "root")() export const ItemComponent = withContext("div", "item")() ``` ```tsx export const RootComponent = withProvider((props) => { return }, "root")() export const ItemComponent = withContext((props) => { return }, "item")() ``` If you don't want to use the provided style and `PropsContext` props, or want to handle the logic, use `component`. ```tsx export const RootComponent = component((props) => { const [context, computedProps] = useRootComponentProps(props, "root") return ( ) }, "root")() export const ItemComponent = component((props) => { const computedProps = useSlotComponentProps(props, "item") return }, "item")() ``` #### Use modifiers To use modifiers, set the slot name to an array. ```tsx const componentStyle = defineComponentSlotStyle({ base: { root: { /* base root style */ }, item: { /* base item style */ }, start: { /* base start style */ }, end: { /* base end style */ }, }, }) ``` ```tsx export const StartItemComponent = withContext("div", ["item", "start"])() export const EndItemComponent = withContext("div", ["item", "end"])() ``` In this case, the style of `item` and `start` or `end` is set, and the class name is `"{prefix}-{name}__item--start"` or `"{prefix}-{name}__item--end"`.