Component Styles
Maintaining flexible styles for components in a growing project can be a challenging task.
To solve this, Yamada UI structures each component with base styles and modifier styles. This allows for flexible style changes.
Additionally, to manage the styles of your custom components with themes, Yamada UI provides useComponentStyle
and useComponentMultiStyle
to retrieve component styles.
Base Styles and Modifier Styles
Most components consist of base styles and modifier styles that change visuals and sizes based on properties.
Common modifier styles include:
Size
: Components can have various sizes (small, medium, large, etc.).Variant
: Components can have various visuals (outline, solid, ghost, etc.).Color Scheme
: Specific variants allow components to have different color schemes.Color Mode
: Components can change styles based on the color mode (light or dark).
There is also an order in which styles are set.
The order is as follows, and the values of the same property will be overwritten:
Base Styles
Size
Variant
Color Scheme
and Color Mode
are values that supplement modifier styles and are not styles themselves.
Single part and multi part components
Yamada UI components are either single-part components (Button
, Link
, etc.) or multi-part components (Tab
, Menu
, etc.).
Single part components
Single-part components consist of a single element. For example, the Button
component renders the HTML element button
.
<Button>Click me!</Button>
Some components may appear to be single-part components but internally switch elements based on conditions, making them multi-part components. Examples include Tag
, Checkbox
, Radio
, etc.
Multi part components
Multi-part components consist of multiple elements. Child elements are dependent on the parent element. For example, the List
component is composed of ListItem
and ListIcon
.
<List><ListItem>よろしければわたしが喜びのダンスを踊りましょうか!</ListItem><ListItem>お命頂だい!!! とうっ!!!</ListItem><ListItem>う…宇宙一のスピードを誇るオ…オレさまのうしろに……</ListItem><ListItem>オ…オレたちが勝てるわけはなかったはずだ………</ListItem><ListItem>オレは試合場のゴミ拾いみたいなもんかよ…</ListItem></List>
Styling Single part components
Before styling, please check Theme Operations and Changing the Style of Components.
Changing the Style of Components was about styling with the default theme inherited.
This time, we will style a new Button
.
./theme/components/button.ts
export const Button: ComponentStyle<"Button", ButtonProps> = {// Styles for the base style.baseStyle: {lineHeight: 1.2,fontWeight: "semibold",transitionProperty: "common",transitionDuration: "slower",},// Styles for the size variations.variants: {solid: {bg: ["gray.500", "gray.200"],color: ["white", "gray.800"],},outline: {borderWidth: "1px",},},// Styles for the visual style variations.sizes: {sm: {h: 8,minW: 8,fontSize: "sm",px: 3,},md: {h: 10,minW: 10,fontSize: "md",px: 4,},lg: {h: 12,minW: 12,fontSize: "lg",px: 6,},},// The default `size` or `variant` values.defaultProps: {variant: "solid",size: "md",},}
Next, we will support dynamic Color Schemes
. To receive Color Schemes
from the component, use a function.
./theme/components/button.ts
export const Button: ComponentStyle<"Button", ButtonProps> = {// Styles for the base style.baseStyle: {lineHeight: 1.2,fontWeight: "semibold",transitionProperty: "common",transitionDuration: "slower",},// Styles for the size variationsvariants: {solid: ({ colorScheme: c }) => ({bg: [`${c}.500`, `${c}.200`],color: ["white", `${c}.800`],}),outline: ({ colorScheme: c }) => ({borderWidth: "1px",borderColor: [`${c}.600`, `${c}.300`],}),},// Styles for the visual style variations.sizes: {sm: {h: 8,minW: 8,fontSize: "sm",px: 3,},md: {h: 10,minW: 10,fontSize: "md",px: 4,},lg: {h: 12,minW: 12,fontSize: "lg",px: 6,},},// The default `size` or `variant` values.defaultProps: {variant: "solid",size: "md",colorScheme: "gray",},}
The function can also retrieve theme
, colorMode
, and props
in addition to colorScheme
.
Set the style of the created component in the theme.
./theme/components/index.ts
import { Button } from "./button"export const customComponents = { Button }
./theme/index.ts
import { extendTheme, defaultTheme, UsageTheme } from "@yamada-ui/react"import { customComponents } from "./components"const defaultComponents = defaultTheme.componentsconst customTheme: UsageTheme = {components: { ...defaultComponents, ...customComponents },}export const theme = extendTheme(customTheme)({ omit: ["components"] })
Styling Multi part components
Before styling, please check Theme Operations and Changing the Style of Components.
Changing the Style of Components was about styling with the default theme inherited.
This time, we will style a new List
.
Multi-part components are styled for each part tied to a key
.
./theme/components/list.ts
export const List: ComponentMultiStyle<"List", ListProps> = {// Styles for the base style.baseStyle: {container: {},item: {lineHeight: 1.2,rounded: "md",},icon: {me: "2",display: "inline-block",verticalAlign: "middle",},},// Styles for the size variationsvariants: {solid: {item: { bg: ["gray.500", "gray.200"], color: ["white", "gray.800"] },},outline: {item: { borderWidth: "1px" },},unstyled: { item: { rounded: "inherit", lineHeight: "inherit" } },},// Styles for the visual style variations.sizes: {sm: {container: { gap: "sm" },item: { fontSize: "sm" },},md: {container: { gap: "md" },item: { fontSize: "md" },},lg: {container: { gap: "lg" },item: { fontSize: "lg" },},},// The default `size` or `variant` values.defaultProps: {variant: "solid",size: "md",},}
Next, we will support dynamic Color Schemes
. To receive Color Schemes
from the component, use a function.
./theme/components/list.ts
export const List: ComponentMultiStyle<"List", ListProps> = {// Styles for the base style.baseStyle: {container: {},item: {lineHeight: 1.2,rounded: "md",},icon: {me: "2",display: "inline-block",verticalAlign: "middle",},},// Styles for the size variationsvariants: {solid: ({ colorScheme: c }) => ({item: { bg: [`${c}.500`, `${c}.200`], color: ["white", `${c}.800`] },}),outline: ({ colorScheme: c }) => ({item: { borderWidth: "1px", borderColor: [`${c}.600`, `${c}.300`] },}),unstyled: { item: { rounded: "inherit", lineHeight: "inherit" } },},// Styles for the visual style variations.sizes: {sm: {container: { gap: "sm" },item: { h: 8, minW: 8, fontSize: "sm", px: 3 },},md: {container: { gap: "md" },item: { h: 10, minW: 10, fontSize: "md", px: 4 },},lg: {container: { gap: "lg" },item: { h: 12, minW: 12, fontSize: "lg", px: 6 },},},// The default `size` or `variant` values.defaultProps: {variant: "solid",size: "md",colorScheme: "gray",},}
Key
varies by component. To check the key
for each component, refer to the Theme
section on the component's page.
Set the style of the created component in the theme.
./theme/components/index.ts
import { List } from "./list"export const customComponents = { List }
./theme/index.ts
import { extendTheme, defaultTheme, UsageTheme } from "@yamada-ui/react"import { customComponents } from "./components"const defaultComponents = defaultTheme.componentsconst customTheme: UsageTheme = {components: { ...defaultComponents, ...customComponents },}export const theme = extendTheme(customTheme)({ omit: ["components"] })
Setting Common props
for the Entire Application
If you want to set common props
for components across the entire application, use defaultProps
. defaultProps
accepts all the props
provided by the component.
export const Button: ComponentStyle<"Button", ButtonProps> = {defaultProps: {loadingText: "Loading…",},}
With the above settings, the loadingText
of the Button
will be "Loading…"
throughout the application.
Props set in the component will override defaultProps
.
If you want to calculate based on the props set in the component and override the component's props, use overrideProps
.
export const FormControl: ComponentStyle<"FormControl", FormControlProps> = {overrideProps: ({ label, ...rest }) => ({...rest,label: (<><PencilIcon me="1" />{label}</>),}),}
With the above settings, the label
of the FormControl
is newly set based on the provided label
.
Creating Custom Components
Depending on the project, you may need custom components. To manage the styles of these custom components with themes, Yamada UI provides useComponentStyle
and useComponentMultiStyle
.
This time, we will create a single-part component called Banner
.
First, create the component.
import { FC } from "react"import { ui, HTMLUIProps } from "@yamada-ui/react"type BannerOptions = {}export type BannerProps = HTMLUIProps<"button"> & BannerOptionsexport const Banner: FC<BannerProps> = (props) => {return <ui.button {...props} />}
Next, set the Banner
style in the theme.
./theme/components/banner.ts
export const Banner: ComponentStyle<"Banner", BannerProps> = {baseStyle: {// Styles for the base style.},variants: {// Styles for the size variations},sizes: {// Styles for the visual style variations.},defaultProps: {// The default `size` or `variant` values.},}
./theme/components/index.ts
import { Banner } from "./banner"export const customComponents = { Banner }
./theme/index.ts
import { extendTheme, defaultTheme, UsageTheme } from "@yamada-ui/react"import { customComponents } from "./components"const defaultComponents = defaultTheme.componentsconst customTheme: UsageTheme = {components: { ...defaultComponents, ...customComponents },}export const theme = extendTheme(customTheme)({ omit: ["components"] })
It is recommended to use type completion for the created variants
and sizes
. Type completion can be done using the CLI.
Finally, call useComponentStyle
within the component to load the style.
import { FC } from "react"import {ui,HTMLUIProps,ThemeProps,useComponentStyle,omitThemeProps,} from "@yamada-ui/react"type BannerOptions = {}export type BannerProps = HTMLUIProps<"button"> &ThemeProps<"Banner"> &BannerOptionsexport const Banner: FC<BannerProps> = (props) => {const [styles, mergedProps] = useComponentStyle("Banner", props)const rest = omitThemeProps(mergedProps)return <ui.button __css={styles} {...rest} />}
If Banner
were a multi-part component, you would call useComponentMultiStyle
within the component, and the style reference would look like this:
import { FC } from "react"import {ui,HTMLUIProps,ThemeProps,useComponentMultiStyle,omitThemeProps,} from "@yamada-ui/react"type BannerOptions = {}export type BannerProps = HTMLUIProps<"button"> &ThemeProps<"Banner"> &BannerOptionsexport const Banner: FC<BannerProps> = (props) => {const [styles, mergedProps] = useComponentMultiStyle("Banner", props)const rest = omitThemeProps(mergedProps)return (<ui.button __css={styles.container} {...rest}><ui.span __css={styles.icon} />{children}</ui.button>)}
Note that the style is passed to __css
. This is an API similar to sx
, but it has the lowest priority in terms of style. __css
is a prop
used internally by Yamada UI components.
Edit this page on GitHub