こんにちは。齋藤(@wtoddev)です。
久しぶりのQiita投稿になります。(最近、あまり明文化されたアウトプットができていない気がする。気をつけなければ。)
今回は、Vue.js(Nuxt)な環境でデザインシステムやコンポーネントライブラリを実装する上で、レンダリングされて吐き出されるHTMLのタグを任意に変更できるような再利用性の高いButtonコンポーネントの作り方について記したいと思います。
実現したいこと
- UI的に原子的なButtonコンポーネントを作る
- そのコンポーネントを利用する場合に、最終的に吐き出されるHTMLのタグが任意に指定できるようにする(
aタグ
やbuttonタグ
などを選べるようにする)
実証環境
今回の実証環境は以下の通りになります。
├── @nuxt/devtools@0.8.2
├── @nuxt/image@1.0.0-rc.1
├── nuxt@3.7.0
└── sass@1.66.1
実装してみる
Vueのcomponent
要素とis
属性を使用することで実現が可能です。
component
要素とは
component
要素は、動的なコンポーネントを作成するための要素で、is
属性によりHTML要素も生成することができる便利な代物です。
タブがあるUIなど、動的にコンポーネントを切り替えたい場合に有用のようです。
公式ドキュメントはこちらから
使ってみる
<script setup lang="ts">
const props = defineProps ({
asHtml: {
type: [Object, String],
default: 'button',
}
})
</script>
<template>
<component :is="props.asHtml">
<slot />
</component>
</template>
原子的なButtonコンポーネントであり、子コンポーネントとして使用されるCoreButton
では、component
要素を使用し、is
属性をpropsで渡せるように定義をしました。また、テキストを挿入するためにslot
を設けています。
親コンポーネントで使用する
<template>
<div>
<CoreButton as-html="a" href="/">これはリンクです</CoreButton>
</div>
</template>
先程作成したCoreButton
を親コンポーネントで使用してみます。
as-html
には吐き出されてほしいHTMLタグであるを記入します。また、タグ内には表示したい文字列を挿入します。
以上のようにした場合、レンダリング後のHTMLは以下のようになります。
<div>
<a href="/">これはリンクです</a>
</div>
このように、propsたるas-html
で渡した文字列がHTMLのタグとして生成されました。
以上で、実現したいことの実装が完了です。今回は色々と省いた原子的なButtonコンポーネントですが、これを応用することでより多様で再利用性の高いコンポーネントが作成できると思います。
おまけ:buttonタグ
でタイポグラフィが思い通りにならない場合
button
タグを使用してマークアップをした場合に、適切にfont-size
font-weight
を指定しているのにも関わらず、意図しないデザインになることがあります。
調査してみるとaタグ
で同じスタイリングをしているのにも関わらず、buttonタグ
にするとおかしくなってしまうようです。
なぜ起きる?
実はbuttonタグ
をはじめ、フォームで使用するようなHTMLタグでは一部ブラウザでfont-family
やfont-size
を継承しないようになっているのです。
font-weight
についても、Google FontsなどのWebフォントを使用している場合に、font-family
が継承されない影響で適切に指定ができない事象が発生するようです。
解決方法
解決方法は非常にシンプルで、リセットCSSなどでbuttonタグ
のfont-family
を親要素を継承するようにinherit
の値を与えてあげるだけで解消します。
font-size
も場合によっては100%
にすることで、問題が解消するかもしれません。
さいごに
今回は生成されるHTMLタグを任意に変更できるようなコンポーネントをつくる方法と、buttonタグ
のタイポグラフィに纏わる厄介な挙動への対処方法についてご紹介しました。少しでもどなたかの参考になれれば幸いです。
ご精読ありがとうございました。
参考文献
- コンポーネントの基礎 | Vue.js
- ウェブフォームへのスタイル設定 - ウェブ開発を学ぶ | MDN