Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Sidebar: peek & control gaps (transparent inset peek, reduced-motion, external control, peek state, backdrop)

已关闭
#875 0 条评论 0 个 reaction 已指派 1 人 在 GitHub 查看

维护者通常 5 天内回复

@rohanchkrabrty 已经在做这个了。

开始于 2026年9月29日。

  • #925 来自 @rohanchkrabrty —— 未关闭

评估

难度
5/5
预计耗时
一周以上
新手友好度
35/100
Issue 类型
功能
描述清晰度
基本清楚
活跃度
冷清
技术栈
react, typescript

调研方向

从 Sidebar 的根样式以及 Sidebar、Sidebar.Trigger 和 useSidebar 入口点开始。将 inset peek 规则与 floating 和 plain 变体进行比较,然后检查现有的 reduced-motion 保护逻辑和当前的上下文状态。完成的标准是视觉错误和动画行为都得到处理,并且外部控制、peek 回调和 backdrop API 的决策都得到一致实现。

由索引模型根据 Issue 内容生成。

描述

This issue collects several related Sidebar gaps found while building an
inset sidebar with peekOnHover. The first is a concrete visual bug; the rest
are behaviour/API gaps that force consumers to reach around the component.


1. Peek overlay is transparent under variant="inset"

Summary

When a Sidebar uses variant="inset" together with peekOnHover, the peek
overlay renders with a transparent background. Because peek lifts the sidebar
above the page content (shadow + z-index), the content behind it shows
straight through, making the nav unreadable.

The same feature works correctly on variant="floating" and variant="plain",
where the sidebar keeps an opaque background — so this looks like the inset
case was missed in the peek path.

Reproduction
<Sidebar variant="inset" collapsible="hidden" peekOnHover defaultOpen>
  <Sidebar.Header>…</Sidebar.Header>
  <Sidebar.Main>
    <Sidebar.Item leadingIcon={<Home />}>Home</Sidebar.Item>
    {/* …more items… */}
  </Sidebar.Main>
</Sidebar>
  1. Collapse the sidebar (it hides).
  2. Hover the collapsed edge to trigger the peek.
  3. The revealed sidebar is transparent — page content is visible through it.

Happens with collapsible="icon" too; inset is the deciding factor.

Root cause

In the compiled sidebar CSS:

  • Base rule sets an opaque background:
    [data-slot="sidebar"] { background: var(--rs-color-background-base-primary) }
  • inset overrides it to transparent (correct while docked):
    [data-variant="inset"] { background: transparent }
  • The peek rule adds elevation but never restores a background:
    [data-peeking] { box-shadow: var(--rs-shadow-lifted); z-index: …; width: … }

floating never zeroes the background, so its peek stays opaque — hence the
inconsistency.

Suggested fix

Give the peeking overlay an opaque background in the peek rule, independent of
variant:

[data-peeking] {
  background: var(--rs-color-background-base-primary);
}

2. prefers-reduced-motion not honored for the sidebar's own transitions

Apsara already gates dialog, accordion, and announcement-bar transitions behind
@media (prefers-reduced-motion: no-preference), but the sidebar's
width / margin peek & collapse transition on the root is unconditional:

[data-slot="sidebar"] {
  transition: width var(--rs-duration-normal) var(--rs-ease-out),
              margin var(--rs-duration-normal) var(--rs-ease-out);
}

Users who request reduced motion still get the animated peek/collapse.

Suggested fix: wrap the root's transition in the same
prefers-reduced-motion: no-preference guard already used elsewhere in the
library, so it's consistent.


3. Cannot control the sidebar from outside its subtree

Sidebar.Trigger reads the internal useSidebar() context, so it only works
inside <Sidebar>. There's no supported way to toggle the sidebar from
elsewhere in the app — e.g. a top bar, breadcrumb row, or header rendered
outside the sidebar tree.

Consumers who want an external toggle must lift open / onOpenChange into
their own state and re-implement the control, duplicating what the sidebar
already manages.

Suggested options (any one):

  • An imperative handle via ref (sidebarRef.current.toggle() / open() /
    close()).
  • A standalone trigger that targets a sidebar by id.
  • Documenting open / onOpenChange as the supported pattern for external
    control (if that's the intended answer).

4. Peek state (isPeeking) is not exposed to the parent

isPeeking is available on the context via useSidebar(), but only to
descendants inside the sidebar. A parent can't react to a peek starting or
ending — e.g. to render a backdrop, coordinate other UI, or fire analytics.

Today the only way to observe a peek from outside is a CSS
:has([data-peeking]) hack.

Suggested fix: add an onPeekChange(isPeeking: boolean) callback prop,
mirroring onOpenChange.


5. No backdrop option for peekOnHover

When peeking, the sidebar floats above the content with only a shadow. There's
no built-in way to dim or scrim the app behind the peek — a common pattern for
hover-drawers, and it helps the floating panel read as a distinct layer.

Suggested fix: an opt-in peekBackdrop (boolean, or a slot) that renders a
backdrop behind the peeking sidebar. Consumers style the look (color/blur);
Apsara owns the show/hide wiring, which it's uniquely able to tie to the
internal peek state.

主要语言
TypeScript
星标
69
派生
13
平均合并
4 天 4 小时
30 天内合并 PR
27

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

raystack/apsara 的其他 Issue

查看 raystack/apsara 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。