Skip to content

[React] Tooltip コンポーネントの追加 - #954

Open
devin-ai-integration[bot] wants to merge 23 commits into
mainfrom
feature/react/components/add-tooltip
Open

[React] Tooltip コンポーネントの追加#954
devin-ai-integration[bot] wants to merge 23 commits into
mainfrom
feature/react/components/add-tooltip

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

概要

  • CSS パッケージの Tooltip を元に、React の Tooltip コンポーネントを追加
  • Accordion 等と同様の compound component パターン で実装(Tooltip.Root / Tooltip.Trigger / Tooltip.Content

使い方

import { Tooltip } from '@giftee/abukuma-react';

  <Tooltip.Root>
    <Tooltip.Trigger>ホバーしてください</Tooltip.Trigger>
    <Tooltip.Content>ツールチップの説明文</Tooltip.Content>
  </Tooltip.Root>

ホバー / フォーカスで表示、Escape で非表示になります。アイコン単体をトリガーにする場合は Tooltip.Triggeraria-label を渡してください。

追加ファイル

  • packages/react/src/components/tooltip/TooltipRoot.tsx — Root(position prop、ab-Tooltip / ab-Tooltip-{position} クラス付与、表示状態の管理と Escape 制御)
  • packages/react/src/components/tooltip/TooltipTrigger.tsx — Trigger(<button> でレンダリングし、ホバー / フォーカスによる表示制御・aria-describedby 付与・Escape での dismiss を担う)
  • packages/react/src/components/tooltip/TooltipContent.tsx — Content(ab-Tooltip-description クラス・role="tooltip" 付与)
  • packages/react/src/components/tooltip/TooltipContext.tsx — サブコンポーネント間で表示状態・id を共有する Context
  • packages/react/src/components/tooltip/Index.tsx — Root / Trigger / Content の re-export
  • packages/react/src/components/tooltip/Index.spec.tsx — テスト(13件)
  • packages/react/src/components/tooltip/stories/ — Storybook(Base / Direction)
  • packages/react/src/index.tsexport * as Tooltip 追加
  • .changeset/add-tooltip-component.md — minor バージョンアップ

Props

Tooltip.Root

Prop デフォルト 説明
position 'top' | 'right' | 'bottom' | 'left' 'top' ツールチップの表示位置
  • Root / Content<span> の標準属性(className, ref 等)を受け取ります。
  • Trigger<button> の標準属性(className, aria-label, ref, 各種イベントハンドラ等)を受け取ります。type は省略時 "button"。独自のイベントハンドラを渡しても内部の表示制御と両立します。

アクセシビリティ

  • Trigger<button>)に aria-describedbyContentrole="tooltip" / id を付与し、両者を紐付け
  • <button> によりネイティブにフォーカス・キーボード操作が可能
  • ホバー / フォーカスで表示、Escape キーで非表示(WCAG 1.4.13 Dismissible)

注意事項

  • Trigger の中にインタラクティブ要素(<a> / <button>)を入れないでください。<button> の中に置くと不正な HTML(ネスト)になり a11y 違反になります。リンクやボタン自体にツールチップを付けたいケースは、現状の固定 button 実装では非対応です

レビュー時の確認ポイント

  • CSS クラス名(ab-Tooltip, ab-Tooltip-{position}, ab-Tooltip-description)が CSS パッケージと一致しているか
  • compound component の API 設計が Accordion 等の既存パターンと整合しているか
  • Trigger<button> 固定とした設計の是非(render prop ではなく children をそのまま受け取る)
  • アクセシビリティ属性(aria-describedby, role="tooltip")と Escape による dismiss の挙動

スクリーンショット

image

Storybook
image

ユーザ影響

  • 新規コンポーネントの追加のため、既存機能への影響なし

Link to Devin run: https://app.devin.ai/sessions/ba09baaac4c443e786ddd9d60478750e
Requested by: @aidyak


Open with Devin

@changeset-bot

changeset-bot Bot commented Feb 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2d77b08

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@giftee/abukuma-react Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@netlify

netlify Bot commented Feb 19, 2026

Copy link
Copy Markdown

Deploy Preview for design-system-abukuma-css ready!

Name Link
🔨 Latest commit 2d77b08
🔍 Latest deploy log https://app.netlify.com/projects/design-system-abukuma-css/deploys/6a2f63ce4bc3100008dcc65d
😎 Deploy Preview https://deploy-preview-954--design-system-abukuma-css.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Feb 19, 2026

Copy link
Copy Markdown

Deploy Preview for design-system-abukuma-react ready!

Name Link
🔨 Latest commit 2d77b08
🔍 Latest deploy log https://app.netlify.com/projects/design-system-abukuma-react/deploys/6a2f63ce384c62000845f8e6
😎 Deploy Preview https://deploy-preview-954--design-system-abukuma-react.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author
Original prompt from yusei.kaida@giftee.co
Received message in Slack channel #design_system_devin:

@Devin
<https://github.com/giftee/design-system/tree/main/packages/css/src/components/tooltip>
これを元に、tooltipコンポーネントを作ってください。ブランチ名は`feature/react/components/add-tooltip`としてください。
<https://github.com/giftee/design-system/pull/600> と同じような感じでPRを作ってください

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Comment on lines +11 to +17
style={{
display: 'flex',
gap: '80px',
justifyContent: 'center',
alignItems: 'center',
padding: '80px',
}}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[niiiits]
この辺全部 abukuma css の util class で書いていただけると 🙏

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

インラインスタイルを abukuma css の utility class (ab-flex ab-justify-center ab-items-center ab-gap-30 ab-p-30) に置き換えました。

Comment on lines +40 to +41
{children}
<span className="ab-Tooltip-description">{content}</span>

@egurinko egurinko Mar 16, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[imo]
Tooltip の trigger と開いた時の中身は、どちらも好きな React 要素を渡したいのだと思います。
しかし、現状は trigger が children で、中身は props の react node になっていて、若干違和感があります。

そのため、以下のような compound component にするのはいかがでしょうか?

<Tooltip>
  <Tooltip.Trigger>
    <button>ホバーしてください</button>
  </Tooltip.Trigger>
  <Tooltip.Content>
    <strong>カスタム</strong>なコンテンツ
  </Tooltip.Content>
</Tooltip>

こうすることで、どちらも children として同じ扱いをすることが可能です。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ご提案ありがとうございます。compound component パターンへの変更は API 設計に大きく影響するため、@aidyak の判断を仰ぎたいと思います。

現状の実装は CSS パッケージの構造をそのまま React に移植した形ですが、compound component にすることで確かに trigger / content の扱いが統一されますね。@aidyak さん、こちらの方針いかがでしょうか?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

良さそうです!compound componentにするで問題ないです!

devin-ai-integration Bot and others added 4 commits March 31, 2026 16:30
Co-Authored-By: yusei.kaida@giftee.co <yusei.kaida@giftee.co>
Co-Authored-By: yusei.kaida@giftee.co <yusei.kaida@giftee.co>
…irection.stories.tsx

Co-Authored-By: yusei.kaida@giftee.co <yusei.kaida@giftee.co>
Co-Authored-By: yusei.kaida@giftee.co <yusei.kaida@giftee.co>
@aidyak
aidyak force-pushed the feature/react/components/add-tooltip branch from 592558f to b2434be Compare March 31, 2026 07:31
Comment on lines +5 to +11
export type TooltipRootProps = ComponentPropsWithoutRef<'span'> & {
/**
* ツールチップの表示位置
* @default 'top'
*/
position?: 'top' | 'right' | 'bottom' | 'left';
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

❌ Cannot revive Devin session - the session is too old. Please start a new session instead.

Comment on lines +16 to +23
export const TooltipTrigger = forwardRef<
ElementRef<'span'>,
TooltipTriggerProps
>(({ children, ...rest }, forwardedRef) => (
<span ref={forwardedRef} {...rest}>
{children}
</span>
));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ask]
TooltipTrigger を別途コンポーネント化している理由とかってあったりしますか?
class を別途付与しているわけではないので、Trigger はなしにして以下でも良いかなと思いました。

<Tooltip.Root position="top">
    ホバーしてください
    <Tooltip.Content>ツールチップ</Tooltip.Content>
</Tooltip.Root>

@aidyak aidyak Apr 2, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

他のデザインシステムを眺めてて、トリガーがコンポーネントになってることがちらほらあったので、コンポーネントにしてみようかなくらいでした。確かにclassの付与等がないので、なしにしてサクッと書けるようにするで良いと思いました!

https://smarthr.design/products/components/tooltip/

@aidyak
aidyak force-pushed the feature/react/components/add-tooltip branch from de6ac12 to a088890 Compare April 2, 2026 08:29
aidyak and others added 2 commits April 5, 2026 21:36
contentIdを渡してaria-describedbyでコンテキストを共有し、ツールチップとの関係性を確立するようにした
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Tooltip content is always invisible: CSS has opacity: 0; visibility: hidden with no rule to override when open

The .ab-Tooltip-description CSS class (packages/css/src/components/tooltip/index.scss:9-10) permanently sets opacity: 0 and visibility: hidden. The old :hover rules that overrode these (setting opacity: 1; visibility: visible) were removed in this PR. The React component adds an ab-Tooltip--open class to the root when the tooltip is open (TooltipRoot.tsx:31), but no CSS rule exists for .ab-Tooltip--open anywhere in the codebase. As a result, even when TooltipContent renders (when open is true), the <span> is in the DOM but is visually hidden by the CSS — the tooltip will never be visible to users.

How the rendering path works
  1. User hovers trigger → setOpen(true)TooltipContent renders a <span class="ab-Tooltip-description">
  2. CSS always applies opacity: 0; visibility: hidden to .ab-Tooltip-description
  3. No CSS rule overrides this when ab-Tooltip--open is present on the parent
  4. Tooltip is in the DOM but invisible

(Refers to lines 9-10)

Prompt for agents
The .ab-Tooltip-description class has opacity: 0 and visibility: hidden, but the :hover rules that previously overrode these were removed. The React component adds an ab-Tooltip--open class to the root element (TooltipRoot.tsx:31) when the tooltip is open, but there is no corresponding CSS rule.

Two possible approaches:

1. Add a CSS rule that makes the tooltip visible when the open class is present on the parent. For example, add to index.scss:
   &.ab-Tooltip--open .ab-Tooltip-description { opacity: 1; visibility: visible; }
   This would also be the place to add transitions and the arrow pseudo-elements that were removed.

2. Alternatively, since TooltipContent already conditionally renders (returns null when not open), remove the opacity: 0 and visibility: hidden from .ab-Tooltip-description entirely, since visibility is now controlled by React state (mount/unmount) rather than CSS. This is the simpler approach but means the CSS package no longer provides any show/hide behavior for non-React consumers.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

修正済み

aidyak and others added 3 commits April 30, 2026 10:01
マウスホバーはCSSの:hover、キーボードフォーカスはReactのopen state +
インラインスタイルで表示を制御する構成に変更。Contentを常にDOMに保持
することでaria-describedbyの参照先が常に有効になる。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
WAI-ARIAのtooltipパターンに従い、TriggerにonKeyDownを注入して
Escape押下時にopen stateをfalseにする。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
spanは標準でフォーカス不可のため、tabIndex={0}を付けないと
TriggerがTriggerに注入するonFocus/onBlur/onKeyDownが発火しない。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
aidyak and others added 5 commits April 30, 2026 10:19
autodocsはRender Propsを正しく抽出できず、Triggerが空タグで
表示されてしまうため、parameters.docs.source.codeで正しいJSXを
明示する。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CSSの:hoverによる表示も含めてEscapeで閉じられるよう、TooltipRootに
documentレベルのkeydownリスナーをopen中だけ張る。Reactで管理する
dismissed stateとインラインスタイルでCSSの:hoverを上書きするため、
CSS自体には変更を加えない。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
import順をeslint --fixで修正し、storybookの<span tabIndex={0}>には
no-noninteractive-tabindex を抑止するコメントを付与(Render Props
パターンの柔軟性をデモする意図のため)。Index.spec.tsxの整形も
prettierで反映。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
<Tooltip.Root {...args}>
<Tooltip.Trigger>
{(props) => (
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

storybookへのエラーだったので、柔軟性を示した方が良いという判断で無視するようにしました

@aidyak

aidyak commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Compound Component patternで全体を作りつつ、トリガー部分はRender props patternで構成するようにしました。
これによって、実際に表示されるものを自由に変更できるようにして柔軟性を担保しています。

aidyak and others added 4 commits June 14, 2026 12:29
- ComponentPropsWithoutRef<'button'>でaria-labelやclassName等を受け取れるように
- 自前のイベントハンドラとユーザー指定ハンドラを合成
- ref転送のテストを追加

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants