Carousel
スライド送り UI です。fandhe-frontend-headless-ui の carousel mod は Root / Control / PrevTrigger / NextTrigger / ItemGroup / Item / IndicatorGroup / Indicator の 8 anatomy パーツと、role="region"・aria-roledescription・自動生成の aria-label を提供します。Themes 版と異なりトランジション CSS やレイアウトを持たず、SSR での属性出力と決定的な状態機械のみを担います。
アクセシビリティ・参考サイトとの対応(イシュー #1660): zag.js(ark-ui の内部実装)と突合し、data-orientation を全 8 パーツへ拡張、item/indicator に data-index(0-origin)、item に data-inview を追加しました。一方、非表示スライドへの aria-hidden 付与は本モジュールが CSS 前提の見た目を持たない SSR 静的マークアップのため意図的に見送っています(非 current を実際に隠さない構成で aria-hidden のみ付けると全スライドが可視のまま支援技術からのみ隠れる不整合になるため)。非 current を CSS で隠す場合は呼び出し側で attrs に ("aria-hidden", "true") を渡してください。同様に aria-controls(trigger → item-group)・各パーツの id/dir も headless-ui に生成機構がないため、必要な場合は item_group の attrs に id、trigger の attrs に aria-controls を明示的に渡す運用とします。
キーボード操作(現状の対応範囲): 状態機械 Carousel は決定的な dispatch action を提供します("next"/"prev" が横向き ArrowRight/ArrowLeft・縦向き ArrowDown/ArrowUp 相当、"first"/"last" が Home/End 相当)。ただし実際のキーボードイベント配線(keydown リスナー登録・orientation に応じたキー選別)は fandhe-frontend-wasm-full(クライアントランタイム)側の後続責務であり、本イシューのスコープ外です。trigger/indicator は native button のためクリック(Enter/Space)は標準の DOM 挙動でカバーされます。
スタイル済みの表示例は Carousel を参照してください。
関連 API: fandhe-frontend-headless-ui API
Demo
枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。
Features
- Root / Control / PrevTrigger / NextTrigger / ItemGroup / Item / IndicatorGroup / Indicator の 8 anatomy パーツを提供する(carousel.rs 冒頭)。
- root は role="region" + aria-roledescription="carousel" + 呼び出し側指定の aria-label を固定出力する(carousel.rs::root)。
- item は role="group" + aria-roledescription="slide" + "{n} of {m}" 形式の aria-label を自動生成する(carousel.rs::item)。
- autoplay 非対応の初期実装のため item_group の aria-live は常に "polite" 固定(carousel.rs::item_group)。
- index==slide_count-1 かつ loop=true のとき Next は先頭へ循環し、prev/next とも disabled にならない決定的な遷移規則を持つ(carousel.rs モジュール doc「決定的な遷移規則」節)。
- zag.js との参照突合(イシュー #1660)により data-orientation を全 8 パーツへ拡張し、item/indicator に data-index(0-origin)、item に data-inview を追加した(carousel.rs モジュール doc「参考サイトとの突合」節)。
- dispatch に Home/End キー相当の "first"/"last"(CarouselAction::First/Last)を追加した(carousel.rs::CarouselAction)。DOM keydown 配線自体は wasm-full 側の後続責務のためスコープ外(下記キーボード操作参照)。
Anatomy
root
item-group
item
control
prev-trigger
indicator-group
indicator
next-triggerAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
root/control/prev_trigger/next_trigger/item_group/item/indicator_group/indicator: orientation | Orientation | — | carousel のレイアウト方向。全 8 パーツが data-orientation を出力する(carousel.rs、イシュー #1660)。 |
root: label | &str | — | aria-label に出力する説明文(carousel.rs::root、必須)。 |
prev_trigger/next_trigger: disabled | bool | false | 端かつ loop=false のとき true(native disabled + data-disabled、carousel.rs::prev_trigger/next_trigger)。 |
item: index, count, current | usize, usize, bool | — | スライド位置・総数・現在表示中かどうか(aria-label/data-index/data-inview/data-current 生成元、carousel.rs::item)。 |
indicator: index, current | usize, bool | — | インジケータの位置・現在位置かどうか(aria-label/data-index/aria-current/data-current 生成元、carousel.rs::indicator)。 |
Carousel::new: index, slide_count, loop_, orientation | usize, usize, bool, Orientation | — | 状態機械の初期値(carousel.rs::Carousel::new)。 |
Data Attributes
| Part | Attribute | Observed Values |
|---|---|---|
control | data-orientation | horizontal |
indicator | data-current | (値なし) |
indicator | data-index | 0, 1, 2 |
indicator | data-orientation | horizontal |
indicator-group | data-orientation | horizontal |
item | data-current | (値なし) |
item | data-index | 0, 1, 2 |
item | data-inview | (値なし) |
item | data-orientation | horizontal |
item-group | data-orientation | horizontal |
next-trigger | data-orientation | horizontal |
prev-trigger | data-disabled | (値なし) |
prev-trigger | data-orientation | horizontal |
root | data-orientation | horizontal |
Examples
Vertical looping carousel
縦方向レイアウト・loop 有効で末尾スライドを表示した例です(Demo は水平・非 loop)。
自前 CSS の最小例
data-scope/data-part/data-orientation/data-current/data-disabled 属性セレクタでトラック移動・インジケータ強調・trigger 減光のスタイルを当てる例です。
利用者が data-scope / data-part / data-orientation / data-current / data-disabled 属性セレクタで自前 CSS を当てる最小例です。headless-ui 自体はスタイルを持ちません(root を表示領域〔overflow: hidden〕、item-group をトラックとして分離し、item_group の style="--fandhe-carousel-index: N" を calc() で参照する transform〔水平は translateX、縦方向は translateY〕で現在位置までスライドを移動します)。
[data-scope="carousel"][data-part="root"] {
overflow: hidden;
width: 100%;
}
[data-scope="carousel"][data-part="item-group"] {
display: flex;
transform: translateX(calc(var(--fandhe-carousel-index) * -100%));
transition: transform 0.2s;
}
[data-scope="carousel"][data-part="item"] {
flex: 0 0 100%;
min-width: 0;
min-height: 0;
overflow: hidden;
}
[data-scope="carousel"][data-part="item-group"][data-orientation="vertical"] {
flex-direction: column;
height: 12rem;
overflow: hidden;
transform: none;
}
[data-scope="carousel"][data-part="item"][data-orientation="vertical"] {
transition: transform 0.2s;
transform: translateY(calc(var(--fandhe-carousel-index) * -100%));
}
[data-scope="carousel"][data-part="indicator"][data-current] {
background: #2563eb;
}
[data-scope="carousel"][data-part="prev-trigger"][data-disabled],
[data-scope="carousel"][data-part="next-trigger"][data-disabled] {
opacity: 0.4;
cursor: not-allowed;
}
Accessibility
WAI-ARIA
| Attribute | Description |
|---|---|
| role="region" / aria-roledescription="carousel" / aria-label | root に固定出力する(carousel.rs::root)。 |
| role="group" / aria-roledescription="slide" / aria-label | item に固定出力し、aria-label は "{n} of {m}" 形式(carousel.rs::item)。 |
| aria-live="polite" | item_group に固定出力する(carousel.rs::item_group)。 |
| aria-label | prev_trigger/next_trigger/indicator に呼び出し側指定または自動生成の説明文を出力する(carousel.rs::prev_trigger/next_trigger/indicator)。 |
| aria-current="true" | indicator が current のときのみ出力する(carousel.rs::indicator。zag.js には存在しない超集合)。 |