Yamada UIにスターをあげる

スター
Yamada UIYamada UIv1.6.3

コンポーネントのスタイル

成長を続けるプロジェクトでコンポーネントのスタイルを柔軟に維持していくのは困難な作業です。

これを解決するためにYamada UIは、各コンポーネントを基本スタイルと修飾子スタイルで構成しています。これにより、柔軟なスタイルの変更を可能にしています。

また、あなたが作成したコンポーネントのスタイルをテーマで管理するために、コンポーネントのスタイルを取得するuseComponentStyleuseComponentMultiStyleを提供しています。

基本スタイルと修飾子スタイル

ほとんどのコンポーネントは、基本スタイルとプロパティに基づいてビジュアルやサイズを変更する修飾子スタイルで構成されています。

一般的な修飾子スタイルには、次のものがあります。

  • サイズ: コンポーネントは、さまざまなサイズ(小・中・大など)を持つことができます。
  • バリアント: コンポーネントは、さまざまなビジュアル(アウトライン・ソリッド・ゴーストなど)を持つことができます。
  • カラースキーム: 特定のバリアントに、コンポーネントは、異なるカラースキームを持つことができます。
  • カラーモード: コンポーネントは、カラーモード(明るい・暗い)に基づいて、スタイルを変更できます。

また、スタイルが設定される順序があります。

順序は以下の通りで、同じプロパティの値は上書きされます。

  1. 基本スタイル
  2. サイズ
  3. バリアント

単一パーツと複数パーツのコンポーネント

Yamada UIのコンポーネントは、単一パーツで構成されるコンポーネント(ButtonLinkなど)と複数パーツで構成されているコンポーネント(TabMenuなど)があります。

単一パーツのコンポーネント

単一パーツのコンポーネントは、単一の要素で構成されるコンポーネントです。例えば、Buttonコンポーネントは、HTML要素のbuttonをレンダリングします。

<Button>Click me!</Button>
Copied!

複数パーツのコンポーネント

複数パーツのコンポーネントは、複数の要素で構成されるコンポーネントです。子要素は、親要素に依存している関係です。例えば、Listコンポーネントは、ListItemListIconで構成されています。

<List>
<ListItem>よろしければわたしが喜びのダンスを踊りましょうか!</ListItem>
<ListItem>お命頂だい!!! とうっ!!!</ListItem>
<ListItem>う…宇宙一のスピードを誇るオ…オレさまのうしろに……</ListItem>
<ListItem>オ…オレたちが勝てるわけはなかったはずだ………</ListItem>
<ListItem>オレは試合場のゴミ拾いみたいなもんかよ…</ListItem>
</List>
Copied!

単一パーツのコンポーネントのスタイリング

コンポーネントのスタイルを変更するは、デフォルトのテーマを継承したスタイリングでした。

今回は、Buttonを新しくスタイリングしていきます。

./theme/components/button.ts

export const Button: ComponentStyle<"Button", ButtonProps> = {
// 基本のスタイル
baseStyle: {
lineHeight: 1.2,
fontWeight: "semibold",
transitionProperty: "common",
transitionDuration: "slower",
},
// ビジュアルのスタイル
variants: {
solid: {
bg: ["gray.500", "gray.200"],
color: ["white", "gray.800"],
},
outline: {
borderWidth: "1px",
},
},
// サイズのスタイル
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,
},
},
// デフォルトの`variant`や`size`などの値
defaultProps: {
variant: "solid",
size: "md",
},
}
Copied!

次に、動的なカラースキームに対応していきます。コンポーネントからカラースキーマを受け取るには、関数を使用します。

./theme/components/button.ts

export const Button: ComponentStyle<"Button", ButtonProps> = {
// 基本のスタイル
baseStyle: {
lineHeight: 1.2,
fontWeight: "semibold",
transitionProperty: "common",
transitionDuration: "slower",
},
// ビジュアルのスタイル
variants: {
solid: ({ colorScheme: c }) => ({
bg: [`${c}.500`, `${c}.200`],
color: ["white", `${c}.800`],
}),
outline: ({ colorScheme: c }) => ({
borderWidth: "1px",
borderColor: [`${c}.600`, `${c}.300`],
}),
},
// サイズのスタイル
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,
},
},
// デフォルトの`variant`や`size`などの値
defaultProps: {
variant: "solid",
size: "md",
colorScheme: "gray",
},
}
Copied!

作成したコンポーネントのスタイルをテーマに設定します。

./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!

複数パーツのコンポーネントのスタイリング

コンポーネントのスタイルを変更するは、デフォルトのテーマを継承したスタイリングでした。

今回は、Listを新しくスタイリングしていきます。

複数パーツのコンポーネントは、各パーツに紐づいているkeyごとにスタイリングしていきます。

./theme/components/list.ts

export const List: ComponentMultiStyle<"List", ListProps> = {
// 基本のスタイル
baseStyle: {
container: {},
item: {
lineHeight: 1.2,
rounded: "md",
},
icon: {
me: "2",
display: "inline-block",
verticalAlign: "middle",
},
},
// ビジュアルのスタイル
variants: {
solid: {
item: { bg: ["gray.500", "gray.200"], color: ["white", "gray.800"] },
},
outline: {
item: { borderWidth: "1px" },
},
unstyled: { item: { rounded: "inherit", lineHeight: "inherit" } },
},
// サイズのスタイル
sizes: {
sm: {
container: { gap: "sm" },
item: { fontSize: "sm" },
},
md: {
container: { gap: "md" },
item: { fontSize: "md" },
},
lg: {
container: { gap: "lg" },
item: { fontSize: "lg" },
},
},
// デフォルトの`variant`や`size`などの値
defaultProps: {
variant: "solid",
size: "md",
},
}
Copied!

次に、動的なカラースキームに対応していきます。コンポーネントからカラースキーマを受け取るには、関数を使用します。

./theme/components/list.ts

export const List: ComponentMultiStyle<"List", ListProps> = {
// 基本のスタイル
baseStyle: {
container: {},
item: {
lineHeight: 1.2,
rounded: "md",
},
icon: {
me: "2",
display: "inline-block",
verticalAlign: "middle",
},
},
// ビジュアルのスタイル
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" } },
},
// サイズのスタイル
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 },
},
},
// デフォルトの`variant`や`size`などの値
defaultProps: {
variant: "solid",
size: "md",
colorScheme: "gray",
},
}
Copied!

作成したコンポーネントのスタイルをテーマに設定します。

./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!

アプリケーション全体で共通のpropsを設定する

アプリケーション全体でコンポーネントの共通のpropsを設定したい場合は、defaultPropsを使用します。defaultPropsは、コンポーネントが提供するpropsをすべて受け入れます。

export const Button: ComponentStyle<"Button", ButtonProps> = {
defaultProps: {
loadingText: "Loading…",
},
}
Copied!

上記の設定で、ButtonloadingTextは、アプリケーション全体で"Loading…"になります。

もし、コンポーネントで設定されたpropsを基に計算し、コンポーネントのpropsを上書きしたい場合は、overridePropsを使用します。

export const FormControl: ComponentStyle<"FormControl", FormControlProps> = {
overrideProps: ({ label, ...rest }) => ({
...rest,
label: (
<>
<PencilIcon me="1" />
{label}
</>
),
}),
}
Copied!

上記の設定で、FormControllabelを設定されたlabelに基づいて、新しくlabelを設定しています。

独自のコンポーネントを作成する

プロジェクトによっては、独自のコンポーネントが必要になる場合があります。その独自のコンポーネントのスタイルをテーマで管理するために、Yamada UIはコンポーネントのスタイルを取得するuseComponentStyleuseComponentMultiStyleを提供しています。

今回は、Bannerという単一パーツのコンポーネントを作成していきます。

まず、コンポーネントを作成します。

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!

次に、テーマにBannerのスタイルを設定します。

./theme/components/banner.ts

export const Banner: ComponentStyle = {
baseStyle: {
// 基本のスタイル
},
variants: {
// ビジュアルのスタイル
},
sizes: {
// サイズのスタイル
},
defaultProps: {
// デフォルトの`variant`や`size`などの値
},
}
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!

最後に、useComponentStyleをコンポーネント内で呼び出し、スタイルを読み込みます。

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!

もし、Bannerが複数パーツのコンポーネントだった場合、useComponentMultiStyleをコンポーネント内で呼び出し、スタイルの参照は下記のようになります。

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!

GitHubでこのページを編集する

テーマをカスタマイズするテーマを切り替える