Leave Yamada UI a star

Star
Yamada UIYamada UIv1.6.4

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:

  1. Base Styles
  2. Size
  3. Variant

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>
Copied!

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>
Copied!

Styling Single part 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",
},
}
Copied!

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 variations
variants: {
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",
},
}
Copied!

Set the style of the created component in the theme.

./theme/components/index.ts

import { Button } from "./button"
export const customComponents = { Button }
Copied!

./theme/index.ts

import { extendTheme, defaultTheme, UsageTheme } from "@yamada-ui/react"
import { customComponents } from "./components"
const defaultComponents = defaultTheme.components
const customTheme: UsageTheme = {
components: { ...defaultComponents, ...customComponents },
}
export const theme = extendTheme(customTheme)({ omit: ["components"] })
Copied!

Styling Multi part 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 variations
variants: {
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",
},
}
Copied!

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 variations
variants: {
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",
},
}
Copied!

Set the style of the created component in the theme.

./theme/components/index.ts

import { List } from "./list"
export const customComponents = { List }
Copied!

./theme/index.ts

import { extendTheme, defaultTheme, UsageTheme } from "@yamada-ui/react"
import { customComponents } from "./components"
const defaultComponents = defaultTheme.components
const customTheme: UsageTheme = {
components: { ...defaultComponents, ...customComponents },
}
export const theme = extendTheme(customTheme)({ omit: ["components"] })
Copied!

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…",
},
}
Copied!

With the above settings, the loadingText of the Button will be "Loading…" throughout the application.

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}
</>
),
}),
}
Copied!

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"> & BannerOptions
export const Banner: FC<BannerProps> = (props) => {
return <ui.button {...props} />
}
Copied!

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.
},
}
Copied!

./theme/components/index.ts

import { Banner } from "./banner"
export const customComponents = { Banner }
Copied!

./theme/index.ts

import { extendTheme, defaultTheme, UsageTheme } from "@yamada-ui/react"
import { customComponents } from "./components"
const defaultComponents = defaultTheme.components
const customTheme: UsageTheme = {
components: { ...defaultComponents, ...customComponents },
}
export const theme = extendTheme(customTheme)({ omit: ["components"] })
Copied!

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"> &
BannerOptions
export const Banner: FC<BannerProps> = (props) => {
const [styles, mergedProps] = useComponentStyle("Banner", props)
const rest = omitThemeProps(mergedProps)
return <ui.button __css={styles} {...rest} />
}
Copied!

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"> &
BannerOptions
export 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>
)
}
Copied!

Edit this page on GitHub

PreviousCustomize ThemeNextSwitching Themes