コンポーネントのスタイル
成長を続けるプロジェクトでコンポーネントのスタイルを柔軟に維持していくのは困難な作業です。
これを解決するためにYamada UIは、各コンポーネントを基本スタイルと修飾子スタイルで構成しています。これにより、柔軟なスタイルの変更を可能にしています。
また、あなたが作成したコンポーネントのスタイルをテーマで管理するために、コンポーネントのスタイルを取得するuseComponentStyle
とuseComponentMultiStyle
を提供しています。
基本スタイルと修飾子スタイル
ほとんどのコンポーネントは、基本スタイルとプロパティに基づいてビジュアルやサイズを変更する修飾子スタイルで構成されています。
一般的な修飾子スタイルには、次のものがあります。
サイズ
: コンポーネントは、さまざまなサイズ(小・中・大など)を持つことができます。バリアント
: コンポーネントは、さまざまなビジュアル(アウトライン・ソリッド・ゴーストなど)を持つことができます。カラースキーム
: 特定のバリアントに、コンポーネントは、異なるカラースキームを持つことができます。カラーモード
: コンポーネントは、カラーモード(明るい・暗い)に基づいて、スタイルを変更できます。
また、スタイルが設定される順序があります。
順序は以下の通りで、同じプロパティの値は上書きされます。
基本スタイル
サイズ
バリアント
カラースキーム
とカラーモード
は、修飾子スタイルを補助する値であり、スタイルではありません。
単一パーツと複数パーツのコンポーネント
Yamada UIのコンポーネントは、単一パーツで構成されるコンポーネント(Button
・Link
など)と複数パーツで構成されているコンポーネント(Tab
・Menu
など)があります。
単一パーツのコンポーネント
単一パーツのコンポーネントは、単一の要素で構成されるコンポーネントです。例えば、Button
コンポーネントは、HTML要素のbutton
をレンダリングします。
<Button>Click me!</Button>
単一パーツのコンポーネントに見えて、内部的には条件分岐で要素を切り替える複数パーツのコンポーネントの場合もあります。例えば、Tag
・Checkbox
・Radio
などが該当します。
複数パーツのコンポーネント
複数パーツのコンポーネントは、複数の要素で構成されるコンポーネントです。子要素は、親要素に依存している関係です。例えば、List
コンポーネントは、ListItem
・ListIcon
で構成されています。
<List><ListItem>よろしければわたしが喜びのダンスを踊りましょうか!</ListItem><ListItem>お命頂だい!!! とうっ!!!</ListItem><ListItem>う…宇宙一のスピードを誇るオ…オレさまのうしろに……</ListItem><ListItem>オ…オレたちが勝てるわけはなかったはずだ………</ListItem><ListItem>オレは試合場のゴミ拾いみたいなもんかよ…</ListItem></List>
単一パーツのコンポーネントのスタイリング
スタイリングをする前に、テーマの運用とコンポーネントのスタイルを変更するをご覧ください。
コンポーネントのスタイルを変更するは、デフォルトのテーマを継承したスタイリングでした。
今回は、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",},}
次に、動的なカラースキーム
に対応していきます。コンポーネントからカラースキーマ
を受け取るには、関数を使用します。
./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",},}
関数は、colorScheme
以外にtheme
・colorMode
・props
を取得することができます。
作成したコンポーネントのスタイルをテーマに設定します。
./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"] })
複数パーツのコンポーネントのスタイリング
スタイリングをする前に、テーマの運用とコンポーネントのスタイルを変更するをご覧ください。
コンポーネントのスタイルを変更するは、デフォルトのテーマを継承したスタイリングでした。
今回は、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",},}
次に、動的なカラースキーム
に対応していきます。コンポーネントからカラースキーマ
を受け取るには、関数を使用します。
./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",},}
key
は、コンポーネントによって異なります。各コンポーネントのkey
を確認するには、コンポーネントのページのテーマ
を参照してください。
作成したコンポーネントのスタイルをテーマに設定します。
./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"] })
アプリケーション全体で共通のprops
を設定する
アプリケーション全体でコンポーネントの共通のprops
を設定したい場合は、defaultProps
を使用します。defaultProps
は、コンポーネントが提供するprops
をすべて受け入れます。
export const Button: ComponentStyle<"Button", ButtonProps> = {defaultProps: {loadingText: "Loading…",},}
上記の設定で、Button
のloadingText
は、アプリケーション全体で"Loading…"
になります。
コンポーネントで設定されたprops
は、defaultProps
を上書きします。
もし、コンポーネントで設定されたprops
を基に計算し、コンポーネントのprops
を上書きしたい場合は、overrideProps
を使用します。
export const FormControl: ComponentStyle<"FormControl", FormControlProps> = {overrideProps: ({ label, ...rest }) => ({...rest,label: (<><PencilIcon me="1" />{label}</>),}),}
上記の設定で、FormControl
のlabel
を設定されたlabel
に基づいて、新しくlabel
を設定しています。
独自のコンポーネントを作成する
プロジェクトによっては、独自のコンポーネントが必要になる場合があります。その独自のコンポーネントのスタイルをテーマで管理するために、Yamada UIはコンポーネントのスタイルを取得するuseComponentStyle
とuseComponentMultiStyle
を提供しています。
今回は、Banner
という単一パーツのコンポーネントを作成していきます。
まず、コンポーネントを作成します。
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} />}
次に、テーマにBanner
のスタイルを設定します。
./theme/components/banner.ts
export const Banner: ComponentStyle = {baseStyle: {// 基本のスタイル},variants: {// ビジュアルのスタイル},sizes: {// サイズのスタイル},defaultProps: {// デフォルトの`variant`や`size`などの値},}
./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"] })
作成したバリアント
やサイズ
は、型補完をすることをオススメします。型補完は、CLIを使用します。
最後に、useComponentStyle
をコンポーネント内で呼び出し、スタイルを読み込みます。
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} />}
もし、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"> &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>)}
スタイルを__css
に渡していることに注意してください。これは、sx
のようなAPIですが、スタイルの優先順位は一番低いものです。__css
は、Yamada UIのコンポーネントで内部的に使用されているprops
です。
GitHubでこのページを編集する