最近のリリースで、Boxは、特定のBox UI Elementsのスタイルをさらにカスタマイズして適用する機能を導入しました。これらのコンポーネントの外観をカスタムアプリケーションに合わせることができるようになっています。この記事では、いくつかのテーマの例とその他のカスタマイズオプションを使用して何ができるかを探っていきます。
Box UI Elementsとは、メインのBoxウェブアプリのコンポーネントを自分のプロジェクトに追加できるようにする、あらかじめ組み込まれたUIコンポーネントです。
デザイントークン
最初に、デザイントークンについて説明します。デザイントークンは、デザイン体系の構築と維持に使用されます。トークンはデータに変換され、製品のエクスペリエンスに一貫性を持たせるための信頼できるソースとして機能します。デザイントークンの対象は、間隔、色、タイポグラフィなどのデザイン要素です。トークンを使用すると、ライトモードとダークモード、利用可能なテーマ、「ブランド」カラーが変わる可能性のあるエンドユーザーと管理者のエクスペリエンスなど、複数のテーマをサポートできます。Box UI Elementsでは、デザイントークンを利用し、値を上書きして、背景色、境界線、アニメーションなど、特定のUI機能の外観を変更できます。
Box UI Elementsのカスタマイズ
Box UI Elementsを初めて使用する場合は、インストールガイドをご覧ください。
現在、デザイントークンを使用してBox Content ExplorerとBox Content Uploaderをカスタマイズできます。これらのElementのいずれかのスタイル設定を開始するには、box-ui-elementsパッケージをバージョン23.3.0にアップグレードするか、CDNリンクを適切に更新する必要があります。
ライブラリの重複を防ぐために、UI Elementsを使用するには、特定のピア依存関係を手動でインストールする必要があります。必要なピア依存関係のリストについては、package.jsonを参照してください。
コンテンツエクスプローラとコンテンツアップローダーのスタイル設定
コンテンツエクスプローラまたはコンテンツアップローダーのスタイルを設定するには、tokensを含むthemeオブジェクトを渡す必要があります。tokensオブジェクトを渡すことができる形式は2つあります。1つは、ケバブケースを使用してトークン名をフラットな構造で記述する方法です。もう1つの方法として、以下のコードサンプルのように、入れ子になった構造を使用することもできます。
const themeLight = {
tokens: {
"background-background": "white"
}
};
// nested structure format
const themeDark = {
tokens: {
Background: {
background: "black"
}
}
};
const contentExplorer = new Box.ContentExplorer();
contentExplorer.show(configData.FOLDER_ID, configData.ACCESS_TOKEN, {
container: ".container",
theme: themeLight,
});
次の対話型のデモをご確認ください。
Box UI Elementsのカスタマイズ可能なプロパティを挙げると、長いリストになります。いくつかのカスタマイズオプションを詳しく見ていきましょう。
最上位のトークン
上書きできる最上位の変数は複数あり、主に、半径、間隔、サイズ設定、影などに関連しています。これらの変数は、px、rem、em、%などの有効なCSS単位を受け入れます。
'border-1': '0.0625rem',
'border-2': '0.125rem',
'border-3': '0.1875rem',
'border-4': '0.25rem',
'border-6': '0.375rem',
'border-8': '0.5rem',
'dropshadow-1': '0 0 0.5rem 0 rgba(0, 0, 0, 0.05)',
'dropshadow-2': '0 0.0625rem 0.25rem 0 rgba(0, 0, 0, 0.1)',
'dropshadow-3': '0 0.25rem 0.75rem 0 rgba(0, 0, 0, 0.1)',
'radius-05': '0.125rem',
'radius-1': '0.25rem',
'radius-2': '0.375rem',
'radius-3': '0.5rem',
'radius-4': '0.75rem',
'radius-5': '1rem',
'radius-6': '1.25rem',
'radius-7': '1.5rem',
'radius-8': '1.75rem',
'radius-half': '2rem',
'size-05': '0.125rem',
'size-1': '0.25rem',
'size-2': '0.5rem',
'size-3': '0.75rem',
'size-4': '1rem',
'size-5': '1.25rem',
'size-6': '1.5rem',
'size-7': '1.75rem',
'size-8': '2rem',
'size-9': '2.25rem',
'size-10': '2.5rem',
'size-11': '2.75rem',
'size-12': '3rem',
'size-14': '3.5rem',
'size-15': '3.75rem',
'size-16': '4rem',
'size-18': '4.5rem',
'size-20': '5rem',
'space-05': '0.125rem',
'space-1': '0.25rem',
'space-2': '0.5rem',
'space-3': '0.75rem',
'space-4': '1rem',
'space-5': '1.25rem',
'space-6': '1.5rem',
'space-7': '1.75rem',
'space-8': '2rem',
'space-9': '2.25rem',
'space-10': '2.5rem',
'space-11': '2.75rem',
'space-12': '3rem',
'space-14': '3.5rem',
'space-15': '3.75rem',
'space-16': '4rem',
'space-18': '4.5rem',
'space-20': '5rem',
};
入れ子になったトークン
最上位のトークンの他に、境界線 (Border)、アイコン (Icon)、アウトライン (Outline)、表面 (Surface)、テキスト (Text) などの特定の領域でグループ化された、入れ子になったオブジェクトがあります。
// Tokens related to border colors. These accept valid CSS color values.
Border: {
'checkbox-border': '#6f6f6f',
'checkbox-border-hover': '#4e4e4e',
'checkbox-border-selected': '#0061d5',
'checkbox-border-selected-hover': '#2079e3',
'cta-border-outline': '#000000', // secondary buttons w/ transparent background
'cta-border-outline-disabled': '#646464',
'cta-border-outline-hover': '#000000',
'cta-border-outline-pressed': '#000000',
'cta-border-secondary': '#bcbcbc', // secondary buttons
'cta-border-secondary-disabled': '#e8e8e8',
'cta-border-secondary-hover': '#bcbcbc',
'cta-border-secondary-pressed': '#bcbcbc',
'divider-border': '#e8e8e8', // horizontal line separators
'dropdown-border': '#bcbcbc',
'gridthumbnail-border': '#e8e8e8', // item (file/folder) thumbnails in grid view
'input-border': '#909090', // text inputs
'input-border-error': '#ed3757',
'input-border-focus': '#2486fc',
'input-border-hover': '#6f6f6f',
'search-border': '#f4f4f4', // search inputs
'search-border-hover': '#6f6f6f',
'switch-border': '#bcbcbc',
'switch-border-hover': '#bcbcbc',
'tooltip-border-error': '#f69bab',
},
// Tokens related to fill colors used in icon buttons.
// These accept valid CSS color values.
Icon: {
'cta-icon': '#6f6f6f',
'cta-icon-hover': '#222222',
'cta-icon-pressed': '#222222',
},
// NOTE: For adjusting files and folder icons, check information
// in "Other customization options" section of this article
Outline: {
'focus-on-dark': '#ffffff',
'focus-on-light': '#2486fc', // outline color for focused states
},
// Tokens related to colors for component surfaces.
// These accept valid CSS color values.
Surface: {
'checkbox-surface': '#ffffff',
'checkbox-surface-hover': '#ffffff',
'checkbox-surface-selected': '#0061d5',
'checkbox-surface-selected-hover': '#2079e3',
'cta-surface-icon': 'rgba(0, 0, 0, 0)', // icon buttons
'cta-surface-icon-disabled': 'rgba(0, 0, 0, 0)',
'cta-surface-icon-hover': 'rgba(0, 0, 0, 0.04)',
'cta-surface-icon-pressed': 'rgba(0, 0, 0, 0.08)',
'cta-surface-outline': 'rgba(0, 0, 0, 0)', // secondary buttons w/ transparent background
'cta-surface-outline-hover': 'rgba(0, 0, 0, 0.04)',
'cta-surface-outline-pressed': 'rgba(0, 0, 0, 0.08)',
'cta-surface-secondary': '#ffffff',
'cta-surface-secondary-hover': '#f4f4f4',
'cta-surface-secondary-pressed': '#e8e8e8',
'cta-surface-tertiary': '#ffffff', // link styled buttons
'cta-surface-tertiary-hover': '#f4f4f4',
'cta-surface-tertiary-pressed': '#e8e8e8',
'dropdown-surface': '#ffffff',
'dropdown-surface-error': '#ffffff',
'dropdown-surface-focus': '#ffffff',
'dropdown-surface-hover': '#ffffff',
'illustration-surface-box-neutral': '#0061d5', // illustrations (detailed icons)
'input-surface': '#ffffff', // text inputs
'input-surface-error': '#ffffff',
'input-surface-focus': '#ffffff',
'input-surface-hover': '#ffffff',
'menu-surface': '#ffffff', // dropdown menu options
'menu-surface-focus': '#f4f4f4',
'menu-surface-hover': '#f4f4f4',
'search-surface': '#f4f4f4', // search inputs
'search-surface-focused': '#ffffff',
'search-surface-hover': '#fbfbfb',
'sliderthumb-surface': '#0061d5', // range sliders
'sliderthumb-surface-hover': '#2486fc',
'slidertrack-surface': '#6f6f6f', // range sliders
'surface': '#ffffff', // general background color
'surface-brand': '#0061d5', // primary buttons
'surface-brand-disabled': '#0061d5',
'surface-brand-hover': '#006ae9',
'surface-brand-pressed': '#004eac',
'switch-surface': '#ffffff',
'switch-surface-off': '#d3d3d3',
'switch-surface-on': '#0061d5',
'tooltip-surface': '#4e4e4e',
'tooltip-surface-error': '#fdebee',
},
// Tokens related to text colors. These accept valid CSS color values.
Text: {
'cta-link': '#0061d5', // hyperlinks
'cta-link-disabled': '#b2cff2',
'cta-link-hover': '#1d6bca',
'cta-link-pressed': '#2486fc',
'text-error-on-light': '#d5324e',
'text-on-dark': '#ffffff',
'text-on-light': '#222222', // primary texts
'text-on-light-secondary': '#6f6f6f', // secondary texts
'text-on-light-secondary-hover': '#4e4e4e',
}
};
テキストのスタイル設定については、さらにCSSルールの追加が必要になる場合があります。
font-family: FONT_NAME;
}
近い将来、カスタマイズ用のトークンをさらに追加する予定です。最新の更新情報と利用可能なすべてのデザイントークンの詳細なリストについては、Developerドキュメントを確認してください。
トークンオブジェクトへのグローバルCSS変数の取り込み
ここでは、CSS変数をBox UI Elementsに取り込む方法の簡単な例を紹介します。CSSファイルにグローバル変数がいくつかあるとします。
--periwinkle: #D2E1FF
--primary: var(--periwinkle);
}
getPropertyValueメソッドを使用してこれらの変数を取得し、これをテーマオブジェクトに渡してトークンオブジェクトに渡すことができます。
const primaryColor = bodyStyles.getPropertyValue('--primary');
const theme = {
tokens: {
"background-background": `${primaryColor} !important`
}
};
const contentExplorer = new Box.ContentExplorer();
contentExplorer.show(configData.FOLDER_ID, configData.ACCESS_TOKEN, {
container: ".container",
theme: theme,
});
その他のカスタマイズオプション
Box UI Elementsでは、さらなるカスタマイズが可能です。フォルダやファイルのアイコンの更新、カスタム操作、カスタムロゴの追加、イベントリスナーの使用、インターセプタの利用などについて、何ができるかを探ってみましょう。
ファイルやフォルダのアイコンのカスタマイズ
ファイルやフォルダのアイコンのスタイルを設定したり、別のSVGに置き換えたりする場合は、DOM内の特定の要素を対象にして行うことができます。そのためには、以下の手順に従います。
- スタイルを設定するアイコンのaria-labelを特定します。ブラウザの開発者ツールを使用してDOMを調査し、SVG要素のaria-label属性を検索します。
- 以下のCSSセレクタパターンに従い、CSSを使用してSVGを対象にします。
- path要素のfillプロパティを希望する色に設定します。ブラウザの開発者ツールを使用して、更新する必要があるpath要素を特定すると便利です。
次の例では、Collaborated folderアイコンの色を変更する方法を示しています。
path:nth-child(1) {
fill: pink;
}
path:nth-child(2) {
fill: plum;
}
}
詳細な例については、こちらのCodePenを確認してください。
カスタム操作
最近、Box UI ElementsであるコンテンツエクスプローラとContent Pickerでファイルやフォルダにカスタム操作を追加できるようになりました。ユーザーが省略記号ボタンをクリックしたときに表示されるメニューで利用可能なオプションを簡単に拡張できます。

これを行うには、カスタム操作の配列をitemActionsに渡します。
container: ".container",
itemActions: customActions,
});
この配列には複数の操作を含めることができます。操作オブジェクトには、label、onActionコールバック関数を含める必要があります。また、fileまたはfolderの値を渡すことで、特定の項目のtypeのみに表示されるようオプションにフィルタをかけることもできます。さらに、ユーザーが特定のファイル拡張子でフィルタをかけたい場合など、より詳細なフィルタを実行するには、filterを使用します。
{
label: "Preview in New Window",
onAction: (item) => alert('action ' + item),
type: 'file',
},
{
label: "Open in Box.com",
onAction: (item) => window.open("https://app.box.com"),
},
{
label: "Export",
onAction: (item) => console.log('action ' + item),
filter: (item) => item.extension?.toLowerCase() === 'pdf',
}
];
実装例については、こちらのCodePenを確認してください。
カスタムロゴ
各Box UI Elementsでは、埋め込まれたコンテナの左上に配置するカスタムロゴを指定できます。たとえば、コンテンツプレビューで独自のロゴを使用するには、logoUrlを渡すだけです。
preview.show(fileId, accessToken, {
container: '.preview-container',
logoUrl: 'URL',
});
画像ファイルの高さは最大32ピクセル、幅は最大80ピクセルになります。さらに大きな画像は、このサイズに合うように縮小されます。
イベントリスナーとカスタム操作
Box UI Elementsの外観以外をカスタマイズする場合は、カスタムイベントハンドラを作成するためにフックできるイベントがあります。
* Adds an event listener to the content explorer. Listeners should be added
* before calling show() so no events are missed.
*
* @param {string} eventName - Name of the event
* @param {Function} listener - Callback function
* @return {void}
*/
contentExplorer.addListener(eventName, listener);
/**
* Removes an event listener from the content explorer.
*
* @param {string} eventName - Name of the event
* @param {Function} listener - Callback function
* @return {void}
*/
contentExplorer.removeListener(eventName, listener);
/**
* Removes all event listeners from the content explorer.
*
* @return {void}
*/
contentExplorer.removeAllListeners();
各Box UI Elementに用意されている一連のイベントは異なるため、詳細な仕様についてはDeveloperドキュメントサイトで確認してください。
Box UI Elementsとインターセプタ
カスタマイズのエッジケースについては、Box UI Elementsとインターセプタの使用を検討してみてください。インターセプトは、クライアントとBox APIの間の通信を円滑にするためにBox UI Elementsで使用されるAxiosライブラリに含まれています。詳細については、次の記事をご覧ください。
最新情報についてはぜひBox開発者向けブログと変更ログをフォローし、今後のリリースにもご期待ください。
🦄 Box Platformの他のエキスパートと交流したい場合は、サポートや知識共有のためのBox Developer Community (英語のみ) にご参加ください。
- トピックス:
- 開発者