Blazorは、Microsoftが提供するC#と. NETを使用して、リッチでインタラクティブなWebアプリケーションを作成するためのフレームワークです。
これにより、JavaScriptを使用せずにフロントエンドのロジックをC#で記述できるため、.NET開発者にとってフルスタック開発がより簡単に実現します。
Blazorでは、UIは「コンポーネント」と呼ばれる小さな単位に分割されています。それぞれのコンポーネントは名称や仕組みは異なっているものの、独立して動作し再利用可能です。
この仕組みを活用することでアプリケーションが複雑になった際でも、コードの整合性や保守性を高く保つことができます。
最近、Webアプリケーションで通知に関するフォーム・コンポーネントの実装タスクに取り組む機会があり、Blazorの利点とユニークな仕組みを活用する方法を学びました。今回初めてBlazorを操作するのにあたり、BlazorとModal機能の説明を備忘録・作成手順として共有します。
- 環境
 - 対象読者
 - フロントエンド開発におけるBlazorの必要性
 - Modal(モーダル)の基本概念と特徴
 - フロントエンド開発におけるModalの必要性
 - BlazorでModalを実装する利点
 - 実践:BlazorでModal機能を実装する方法
 - トラブルシューティングと対応
 - まとめ
 - 参考資料
 
環境
本記事で使用する開発環境は以下の通りです。
- Blazor Server (.NET 8)
 - Microsoft Visual Studio Enterprise 2022 (64-bit) Version 17.12.5
 
環境構築に必要な条件をご確認の上、参考にしてください。
対象読者
本記事は、下記の知識や経験を持った方を対象としています。
- 開発者としての基本的なC#の知識
 - .NETフレームワークに関する基礎理解
 - Blazorを操作した経験
 
フロントエンド開発におけるBlazorの必要性
上記でも説明しましたが、Blazorを利用することで、JavaScriptなしでもWebアプリケーションを開発することができます。特に、Modal機能をC#で構築できるため、統一された開発フローを維持でき、開発者にとっての負担が軽減されます。
Modal(モーダル)の基本概念と特徴
Modal(モーダル)は、ユーザーインターフェース(UI)デザインにおける非常によく使われるパターンの一つで、「画面全体の一部を覆い、重要な情報や操作を提示するポップアップウィンドウ」のようなものです。

たとえば、次のような場面で使用されます。
- 確認ダイアログ(例: 「本当に削除しても良いですか?」)
 - 詳細フォームの入力
 - 追加情報の表示(例: 「ヘルプ」や「詳細を見る」機能)
 
Modalの特徴:
1. フォーカスを制御する
Modalが表示されている間は、親画面の操作が一時中断されます。つまり一旦何らかの方法でModalを解除する必要があります。これはユーザーに重要な情報や選択を明確に提示し、注意を引くことができます。
2. デザインの一貫性
Modalのデザインは、アプリケーション全体のスタイルに合わせて作成できるためある程度一貫性のあるUXを提供できます。
3. 柔軟性
Modalは・ログインフォーム・アラート・詳細ビューなど、アプリケーションのさまざまな場面で汎用的に使用できる柔軟性を持っています。
フロントエンド開発におけるModalの必要性
フロントエンド開発では、UIとUXの向上が常に求められています。Modalは、ユーザーが重要な情報を見逃さないようにするための強力なツールで、通知や確認メッセージの伝達に欠かせません。
BlazorでModalを実装する利点
Blazorでは、ModalのようなUIコンポーネントを簡単に実現することができます。以下にいくつかの利点を挙げてみます。
1. コンポーネントベースのデザインの利用
Blazorはコンポーネントベースのフレームワークであり、Modalもカスタムコンポーネントとして簡単に作成できます。一度作成したModalコンポーネントは、プロジェクト内のあらゆる場所で再利用でき、コードの重複を削減できます。
例として、次のような基本的な構造でModalを作成できます:
<div class="modal" tabindex="-1">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Modal title</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <p>Modal body text goes here.</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>

※上記の画像がModalの基本的なレイアウトですが、カラーリング変更はもちろんテキスト配置の変更、ボタンの増減、フルスクリーン化など様々なカスタマイズが可能です。
2. 状態管理を簡単に実現
Blazorでは、状態管理(@code セクションでのC#コード)を利用して、Modalを表示・非表示にするロジックを記述できます。例えば、ボタンがクリックされたときにModalを表示するという動作を、C#コード内で簡単に定義できます。
※@code セクション内ではC#コードを記述することによりロジックを制御できるという例です。
@code {
    private bool IsVisible = false;
    void ShowModal()
    {
        IsVisible = true;
    }
    void CloseModal()
    {
        IsVisible = false;
    }
}
実践:BlazorでModal機能を実装する方法
開発環境の事前準備
まず、Visual Studioで新しいBlazor Web Appプロジェクトを作成してください。

※プロジェクト名は任意の名前で問題ありません。

その後に必要なNuGetパッケージをインストールしプロジェクト設定を確認してください。
プロジェクト作成後にVisual Studioのメニューバーから「ツール」→「NuGet パッケージマネージャー」→「パッケージマネージャー コンソール」を選択します。

コンソールに下記3点のコマンドを1つずつ入力します。
- Install-Package Microsoft.AspNetCore.Components.Web -Version 8.0.14
※ 最新バージョンを確認し、適切な互換性のあるバージョン番号を指定してください。 - Install-Package bootstrap -Version 5.3.0
 - Install-Package Blazored.Modal
 

※すでにインストールされている場合は不必要です。
基本的なModalコンポーネントの作成
Modalコンポーネントの基本的なコードスニペットやベースとなるカスタマイズ機能はこちらで記述されています。参考にしてください。
メッセージ表示のためのカスタマイズしたこと
コンポーネントは表示させるだけで終わりではなく、操作をされる対象者を想定しなくてはいけません。
また、このアプリケーションをただ作成するだけでなく、UIとして軽微な工夫を追加しました。
1. 長い単語と改行の折り返し設定
長い文章を入力したときはデフォルトだと文章が見切れてしまうことがわかりました。
そこで折り返し、とスクロールの設定を追加し全文がスムーズに確認できるようにしました。

.modal-body-content {
    word-wrap: break-word; /* 長い単語の折り返し */
    white-space: pre-wrap; /* 改行とスペースを保持して折り返し */
    overflow-y: auto; /* コンテンツが溢れる場合にスクロールを追加 */
}
2. Modalの高さを固定
上記1.に付随する設定として高さの固定も追加しました。
そもそも文章量によりModalのサイズが変わる点がUIとして改善点があると考えたためです。つまりCloseボタンの位置も内部の文章量によって変わってしまうおそれがあるためです。
これによりたとえ文字数が1文字でも1000文字でもCloseボタンの位置は固定となりスムーズに操作することができます。
.modal-content {
    height: 300px; /* モーダル全体の高さを固定 */
}
3. Closeボタンのクリック無効時間(反映の遅延として)を設定
通常レスポンスは早ければ早いほうが良いというのは基本的な考え方です。
ただし、今回作成したModalは複数のメッセージを表示させる機能も組み込んでいます。
例えば下図の場合だと(2/3)と表示されていますが、「全体3点のメッセージを表示しそのうち現在の画面は2枚目」という意味となります。
このまま通常通りCloseをクリックする場合、内容を確認せずとも3回の素早いクリックで実質的なスキップが可能です。
そのため下記コードの設定を行いました。「await Task.Delay(500);」というのは
0.5秒の無効(遅延)時間を設定したという意味になり、連続クリックを無効にしました。
これにより読み飛ばしを防ぐことができます。

StateHasChanged();
isWaitActive = true;
await Task.Delay(500);
isWaitActive = false;
トラブルシューティングと対応
開発中にあったエラーとその対策
BlazorでModalコンポーネントを使用する際によく発生するエラーと、その解決方法を簡単にまとめました。初心者の方でも対応しやすいように、ポイントを絞って説明します。
1. NullReferenceException が発生する
Modalの状態を管理する変数やプロパティが初期化されていない場合に発生します。
解決方法として、Modalの表示状態を管理する変数を初期化します。
private bool IsModalVisible = false;
2. Modalが正しく表示されない
開発している環境やプロジェクトに依存しますが、名前空間や依存性注入(Dependency Injection)を適切に設定していないとModalが正しく表示されません。
解決方法として、名前空間や依存性注入を適切に設定します。
3. ボタンをクリックしてもModalが閉じない
ボタンのクリックイベントが正しく設定されていない場合、Modalを閉じる機能が動作しません。
解決方法として、ボタンに正しいイベントをバインドします。
<!-- ボタンのコード -->
<button class="btn btn-secondary">Close</button>
<!-- バインドするメソッド -->
private void HideModal()
{
    IsModalVisible = false;
}
4. Stateが更新されない
データが変更されても画面に反映されない場合があります。
解決方法として、状態変更後に StateHasChanged() を呼び出します。
private void UpdateModalData()
{
    ModalData.SomeProperty = "New Value";
    StateHasChanged();
}
Modalコンポーネントを使ったアプリ開発でエラーが発生した場合、ここで紹介したポイントを順番に確認してみてください!
まとめ
ここではModalのコンポーネントのみに焦点を当てましたが、単純な通知や確認メッセージの提供以外にも、ユーザー入力を効果的に管理したりリアルタイムデータの表示を行ったりするなど、その用途は非常に多岐にわたります。
また、Blazorの利点であるC#による状態管理との親和性が高く、たとえばSignalRなどを組み合わせることで、リアルタイムに内容が変化するModalを構築することも不可能ではありません。
さらに、デフォルトのBootstrapスタイルをそのまま使うのではなく、独自のCSSを適用したり、開閉のアニメーションなど追加したりすると視覚的な魅力が向上しModalがよりユニークになります。
今回の開発の際には、複数Modalがスタックされることを想定したコンポーネントを作成する必要があったため少し試行錯誤した時間はありました。ある程度実装の知識がついてくると他のコンポーネントとの連携を事前に考慮することができ、よりスムーズな運用が可能になると思います。
BlazorのModalは、設計と実装次第でその機能性と利便性が大きく広がります。今回の内容を参考に、Modalが持つ可能性を最大限に活かし、ユーザーにも開発者にも優しいWebアプリケーションを構築してください。
参考資料
- Blazor公式ドキュメント
 - Blazor | C# を使用したクライアント Web アプリケーションのビルド | .NET
 - 『Blazor入門』(技術評論社)
 - モーダル · Bootstrap v5.3
 
前田 将太(日本ビジネスシステムズ株式会社)
BS事業本部 先端技術部に所属。 AI,ComputerVison,VRに興味があります。 前職ではRPAで処理自動化・業務改善を担当していました。
担当記事一覧