生态产品多个设计器现已发布候选版本

查看生态总览
跳转到内容

SideNav 侧栏导航 ​

用于组织应用的主要导航入口。

用法 ​

组织应用的主要导航入口

组件结构 ​

加粗的是必需部件。

data-scope="side-nav":root · input · list · item · group · group-label · group-list · branch · branch-trigger · branch-text · branch-indicator · positioner · branch-content · link · link-text · empty

示例 ​

折叠模式 ​

以图标保留入口,子级在浮层中展开

尺寸 ​

适配不同密度的应用侧栏

禁用项 ​

保留不可用入口的位置与说明

搜索过滤 ​

输入即按标签过滤导航树,命中入口的祖先自动展开,其余收起;Escape 清空检索词

图标栏名称提示 ​

折叠成图标栏后,悬停或聚焦只剩图标的入口时在旁侧显示它的名称

设计指引 ​

何时使用 ​

  • 管理后台或控制台的主导航。
  • 导航包含分组或可展开的子级。

何时不用 ​

  • 顶部横向导航,使用导航菜单。
  • 文件或组织结构,使用树。

特性 ​

  • 支持分组、嵌套分支与当前项高亮:当前项铺品牌淡底行面、字取淡底前景,不另画指示条;通往当前项的展开分支只落与悬停同档的中性面。
  • accordion 限制同一层级只展开一个分支。
  • 入口可逐条声明语气,不向下传导;当前项的品牌淡底压过它。
  • 折叠后保留图标入口,子级在浮层中展示。
  • 放一个 tooltip 部件,折叠成图标栏后只剩图标的入口(顶层叶子;collapsedPopout 关掉时也含顶层分支)悬停或聚焦时在行尾一侧显示名称。它就是库内的 文字提示:悬停延时、接替窗口、提示组与外观都与 Tooltip 一致,放在 XhTooltipProvider 里同样归那一组;弹出分支的面板自己就是去处,不再叠一层提示。
  • 方向键上下移动,左右键展开或收起分支。
  • 放一个 input 即可按标签过滤导航树:命中入口的祖先保留并展开,没命中的整行、整枝收起,分组的成员一个都没命中就整组收起;filter 可换成自定义匹配。
  • 命中的入口整枝留下:分支本身命中时,它的子项照常在里面,不因命中而自动展开。
  • 搜索里的展开收起只记在搜索视图里,不改写 expandedValue、也不发 expanded-value-change;清空检索词即回到整棵树与原来的展开态。
  • 一条都没命中时 empty 露面;没写内容时显示 translations.noMatch。
  • 折叠成图标栏时过滤暂停,搜索框留着高度但不可见、不可聚焦,展开回来接着按原词过滤。

组合 ​

  • 放入布局的侧栏区域。
  • 分组:group 放在 list 里当一条,里面先放 group-label,再放 group-list,组内的 item 与 branch 挂在 group-list 里。
  • Vue / React 的 XhSideNavGroupList 从所在的 XhSideNavGroup 取分组身份,不用再写 value;Web Components 的 group-label 与 group-list 都认所在的 group。
vue
<XhSideNavList>
  <XhSideNavGroup value="main">
    <XhSideNavGroupLabel value="main">常用</XhSideNavGroupLabel>
    <XhSideNavGroupList>
      <XhSideNavItem>
        <XhSideNavLink value="home">
          <XhSideNavLinkText>工作台</XhSideNavLinkText>
        </XhSideNavLink>
      </XhSideNavItem>
    </XhSideNavGroupList>
  </XhSideNavGroup>
</XhSideNavList>
tsx
<XhSideNavList>
  <XhSideNavGroup value="main">
    <XhSideNavGroupLabel value="main">常用</XhSideNavGroupLabel>
    <XhSideNavGroupList>
      <XhSideNavItem>
        <XhSideNavLink value="home">
          <XhSideNavLinkText>工作台</XhSideNavLinkText>
        </XhSideNavLink>
      </XhSideNavItem>
    </XhSideNavGroupList>
  </XhSideNavGroup>
</XhSideNavList>;
html
<ul data-xh-part="list">
  <li data-xh-part="group" value="main">
    <div data-xh-part="group-label">常用</div>
    <ul data-xh-part="group-list">
      <li data-xh-part="item">
        <a data-xh-part="link" value="home"><span data-xh-part="link-text">工作台</span></a>
      </li>
    </ul>
  </li>
</ul>

接路由 ​

  • Vue / React 的 link 缺省渲染 <a>,href 由作者写或取自 collection。接客户端路由时给 XhSideNavLink 加 asChild,把路由链接放进去当唯一的子节点:部件属性、按压与聚焦接线合到它渲出的元素上,跳转交给路由;子节点不是恰好一个元素时直接报错。
  • 当前项跟着路由走:把当前路径换算成 value 受控传入。点选只发 value-change,真正的当前项仍以路由为准。
  • Web Components 不需要 asChild:link 本来就是作者写的节点,元素只往它身上写属性与监听、不替换它。路由库自己的链接元素,或自行拦截点击的 <a>,直接标 data-xh-part="link" 即可。
vue
<XhSideNavLink value="orders" as-child>
  <RouterLink to="/orders">
    <XhSideNavLinkText>订单</XhSideNavLinkText>
  </RouterLink>
</XhSideNavLink>
tsx
<XhSideNavLink value="orders" asChild>
  <Link to="/orders">
    <XhSideNavLinkText>订单</XhSideNavLinkText>
  </Link>
</XhSideNavLink>;

最佳实践 ​

  • 导航层级保持在两到三级。
  • 折叠模式下为每个入口保留清晰图标。

反模式 ​

  • 不要为单个入口创建分支。
  • 不要在折叠时卸载导航树。

API 参考 ​

产物 ​

层值
自定义元素<xh-side-nav>
Vue 组件XhSideNavBranch XhSideNavBranchContent XhSideNavBranchIndicator XhSideNavBranchText XhSideNavBranchTrigger XhSideNavEmpty XhSideNavGroup XhSideNavGroupLabel XhSideNavGroupList XhSideNavInput XhSideNavItem XhSideNavLink XhSideNavLinkText XhSideNavList XhSideNavRoot XhSideNavTooltip
组合式函数useSideNav
状态机sideNavMachine
皮肤@xihan-ui/styles/side-nav.css

Props ​

属性类型必填说明
collectionSideNavNode[]入口树,层级与文本的唯一事实源。默认为空。
valuestring | null选中的叶子(单选)。提供即受控:cell 直读 prop,写入只发 onValueChange。
defaultValuestring | null
expandedValuestring[]展开集合。提供即受控,语义同上。
defaultExpandedValuestring[]
accordionboolean同层手风琴:展开一枝时收起同层其余分支,默认 false(可多开)。
collapsedboolean折叠为图标栏:内嵌展开整体收起、文字由皮肤隐藏,只剩图标一列。 顶层分支改为浮层弹出:悬停 / 点击 / 右方向键在旁侧弹出子级面板。
collapsedPopoutboolean折叠态下顶层分支是否弹出子级面板,默认 true;关闭即回到纯图标栏。
disabledboolean整个侧栏禁用。
loopboolean上下键到达首尾是否回绕,默认 false。
dirDirection文字方向,默认 ltr;只对调左右方向键的展开 / 收起语义。
toneTone语气:brand / neutral / success / warning / danger / info,决定使用哪族颜色。
sizeSize尺寸:sm / md / lg。
filterSideNavFilter搜索框的匹配规则:检索词按它判定一条入口是否命中;缺省为标签(缺省退回 value)大小写不敏感包含。 命中的入口整枝留下,没命中但有子孙命中的分支只留命中的那几枝并展开,其余收起。
translationsPartial<SideNavTranslations>
onValueChange(details: SideNavValueChangeDetails) => void选中意图回调;受控时是唯一出口,非受控时随内部写入一并通知。
onExpandedValueChange(details: SideNavExpandedValueChangeDetails) => void展开集合变化意图回调;语义同上。

SideNavNode ​

collection 的元素。

字段类型必填说明
valuestring是
labelstring入口文本;默认回退为 value,也是连打检索的取字来源。
disabledboolean入口禁用:方向键跳过它,但它仍可聚焦。不向下传导给子级。
toneTone该入口自身的性质:危险区域写 danger、需要留意的写 warning。不写即与其余入口同档, 也不向下传导给子级——每一层各自声明。只换字色与悬停 / 按下的面,不表达当前页; 当前项的品牌淡底与禁用都压过它。彩字不是唯一通道,要紧的差别仍要配图标。
hrefstring直达目标;只对叶子有意义。
childrenSideNavNode[]

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
value-changeSideNavValueChangeDetails选中变化;detail 为 { value: string | null }
expanded-value-changeSideNavExpandedValueChangeDetails展开集合变化;detail 为 { value: string[] }

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhSideNavRootdefaultSideNavRootSlotProps

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhSideNavBranchvaluestring是
XhSideNavBranchContentcontainer() => Element | null本分支弹层的 Portal 容器;优先于应用级配置。
XhSideNavGroupvaluestring是分组身份,group-label 与 group-list 依靠它配对。
XhSideNavGroupLabelvaluestring是
XhSideNavLinkvaluestring是
XhSideNavRootchildrenSlotChildren<SideNavRootSlotProps>
XhSideNavTooltipcontainer() => Element | null名称提示的 Portal 容器;优先于应用级配置。

状态 ​

公开状态写入 data-state。

部件取值
branch'open' | 'closed'
branch-trigger'open' | 'closed'
branch-indicator'open' | 'closed'
branch-content'open' | 'closed'
popout-positioner'open' | 'closed'

以下名称仅用于内部状态机。

状态:idle · popout

事件:VALUE.SET · LINK.SELECT · EXPANDED.SET · BRANCH.EXPAND · BRANCH.COLLAPSE · BRANCH.TOGGLE · NODE.FOCUS · FOCUS.CLEAR · POPOUT.OPEN · POPOUT.CLOSE · POPOUT.HOVER · POPOUT.HOVER_END · PRESENCE.SET · PRESS.START · PRESS.END · COLLAPSE.SETTLED · INPUT.CHANGE · TOOLTIP.TARGET · TOOLTIP.OPEN_CHANGE

判据:canChange · canPopout · canPress

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
valuestring | null选中的叶子;尚未选中时为 null。
expandedValuestring[]
collapsedboolean折叠为图标栏;顶层分支改为浮层弹出子级面板。
popoutValuestring | null折叠态下正在弹出子级面板的顶层分支;未弹出时为 null。
openPopout(value: string) => void弹出某顶层分支的子级面板(仅折叠态有效)。
closePopout() => void
focusedValuestring | nullroving tabindex 的锚点;无可见锚点时为 null。
isSelected(value: string) => boolean
isExpanded(value: string) => boolean
isActiveBranch(value: string) => boolean选中项的祖先分支:展开高亮当前所在的分支。
select(value: string) => void
setValue(next: string | null) => void
setExpandedValue(next: string[]) => void
expand(value: string) => void
collapse(value: string) => void
inputValuestring搜索框里的检索词。
setInputValue(next: string) => void改写检索词,与在搜索框里输入同一语义;传空串即回到整棵树与原来的展开态。
searchingboolean正处于搜索视图:检索词非空且排布没有落成图标栏,可见行只剩命中的那几枝。
emptyboolean搜索视图里一条都没命中。
translationsSideNavTranslations合并缺省值之后的读屏文案。
getRootProps() => T['element']
getListProps() => T['element']
getInputProps() => T['input']搜索框:放在 root 里、list 之前。输入即按 filter 过滤导航树;下方向键或 Enter 把焦点交给导航行, Escape 先清空检索词。落成图标栏时过滤暂停(皮肤让框留着高度、不可见也不可聚焦),展开回来接着按原来的检索词过滤。
getEmptyProps() => T['element']搜索一条都没命中时露面的占位,放在 list 之后;其余时候带 hidden。
getItemProps(props?: SideNavItemProps) => T['element']叶子行的列表项容器:链接与分支一样是列表的一条,作者把 link 包在其中。
getGroupProps(props: SideNavGroupProps) => T['element']分组:上一层列表里的一条(li),装着 group-label 与 group-list;搜索时一个成员都没命中就整组收起。
getGroupLabelProps(props: SideNavNodeProps) => T['element']
getGroupListProps(props: SideNavNodeProps) => T['element']分组里的列表(ul):组内的 item 与 branch 挂在这里,以 group-label 命名。
getBranchProps(props: SideNavNodeProps) => T['element']
getBranchTriggerProps(props: SideNavNodeProps) => T['button']
getBranchTextProps() => T['element']行文字的载体:折叠为图标栏时由皮肤整体隐藏,不会裁出半个字。
getBranchIndicatorProps(props: SideNavNodeProps) => T['element']
isPopoutPanel(value: string) => boolean该分支在折叠态下是否以浮层面板出现;决定作者是否需要渲染定位层。
getPopoutPositionerProps(props: SideNavNodeProps) => T['element']弹出面板的定位层。使用引擎坐标、承载层号,作者须把它移到浮层落点, 避免祖先的层叠上下文困住面板。非弹出分支不渲染这一层。
getBranchContentProps(props: SideNavNodeProps) => T['element']
getLinkProps(props: SideNavNodeProps) => T['element']
getLinkTextProps() => T['element']链接文字的载体:折叠时由皮肤整体隐藏。
tooltipTextstring名称提示的文字:对着的那一行在 collection 里的标签(缺省退回 value);还没对着任何一行时为空串。
getTooltipPositionerProps() => T['element']名称提示的定位层:即库内 tooltip 的 positioner(data-scope="tooltip"),坐标、落点与层号由内嵌的提示机给, 作者把它搬到浮层落点。只在 connect 拿到内嵌提示机时可用,否则直接报错。
getTooltipContentProps() => T['element']名称提示本体:即库内 tooltip 的 content,浮层面、进退场与接替窗口都随 Tooltip; 对读屏隐藏(行文字已是可及名,不再念第二遍)。只在 connect 拿到内嵌提示机时可用,否则直接报错。

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
Enter / Spaceheld on link / branch-trigger, 侧栏未禁用且入口未禁用按住期间链接行或分支行投影 data-pressed,与指针 :active 同一副按压面;抬起或失焦撤下,弹出面板随选中收起时一并撤下。导航当前(aria-current)与按压互相独立,激活与展开语义照旧由这一次按键承担
Enter / Spacefocus in branch-trigger展开/收起该枝(原生按钮激活)
Enterfocus in link激活链接(原生行为)并落选中
ArrowDownfocus in 行下一可见行(roving tabindex)
ArrowUpfocus in 行上一可见行
ArrowRightfocus in 收起的分支行展开该枝;已展开时进第一个子行(RTL 与 ArrowLeft 对调)
ArrowLeftfocus in 展开的分支行收起该枝;叶子或已收起时回父分支(RTL 与 ArrowRight 对调)
Homefocus in 行第一可见行
Endfocus in 行最后一可见行
ArrowRight / Enter / Spacefocus in 折叠态顶层分支行弹出子级面板并落焦第一行(RTL 与 ArrowLeft 对调)
ArrowLeft / Escapefocus in 弹出面板收回面板,焦点还给触发按钮(RTL 与 ArrowRight 对调;Escape 归消解层)
可打印字符focus in input改写检索词:导航树裁到只剩命中的那几枝,命中入口的祖先自动展开、其余收起;搜索里的展开收起只记在搜索视图里,不改写 expandedValue
ArrowDown / Enterfocus in input焦点交给导航行:搜索中落在剩下的第一行,不在搜索中落在 Tab 锚点
Tab / ArrowDown / ArrowUp / Home / Endcollapsed 落成图标栏、放了 tooltip 部件,焦点落到只剩图标的行(顶层叶子;collapsedPopout 关掉时也含顶层分支)立即显示该行的名称提示,不走悬停延时;焦点离开即收。提示对读屏隐藏,可及名仍由行文字承担
Escape名称提示显示中收起名称提示,焦点留在行上(Escape 归消解层按层栈仲裁)
Escapefocus in input, 检索词非空清空检索词,回到整棵树与原来的展开态,焦点留在搜索框;检索词已空时不拦截这一下

ARIA ​

以下属性由 connect 生成。

部件属性值
rootaria-labeltranslations.root
rootrole'navigation'
inputaria-controlsscope.partId('side-nav', 'list')
inputaria-labeltranslations.input
group-listaria-labelledbygroup-label 部件的 id
branch-triggeraria-controlscontent 部件的 id
branch-triggeraria-disabled'true' | 'false'
branch-triggeraria-expanded'true' | 'false'
branch-indicatoraria-hidden'true'
branch-contentaria-hidden!open || undefined
linkaria-current'page' | undefined
linkaria-disabled'true' | undefined
emptyrole'status'
popout-positioneraria-hidden!open || undefined
tooltip-contentaria-hidden'true'
tooltip-contentroleundefined
  • list、group-list 与 branch-content 都是列表(ul),直接子节点只放列表项:item 与 branch,list 里还可以放 group。
  • 分组 group 是上一层列表里的一条,本身不带角色;组内的行挂在 group-list 里,group-list 以 aria-labelledby 指向 group-label,读屏念作「标题 + 列表」。不写 role="group":列表项的父节点必须是列表。
  • 将文字放入 branch-text 或 link-text,确保折叠后仍有可访问名称。
  • 装饰图标使用 aria-hidden="true"。
  • 搜索框没有可见标签,可及名取 translations.input;聚焦不画环,插入符就是焦点指示,与级联选择、命令面板的搜索框同一种写法;空态以 role="status" 露面即播报。
  • 图标栏的名称提示对读屏隐藏,行上也不挂 aria-describedby:行文字已是可及名,提示只给看得见的人补上被裁掉的那段字。Escape 收起提示,焦点留在行上。

样式参考 ​

皮肤 ​

@xihan-ui/styles/side-nav.css 按 [data-scope="side-nav"][data-part="root"] 部件选择器书写,发布产物以挂载类 .xh-scope-side-nav 代替其中的 data-scope(特异性相同),位于 xihan.components 层。覆盖样式使用 xihan.overrides,部件选择器照常可用。

forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
rootdata-animating''(条件成立时才出现)
rootdata-collapsed''(条件成立时才出现)
rootdata-disabled''(条件成立时才出现)
rootdata-sizeprops.size
rootdata-toneprops.tone
inputdata-collapsed''(条件成立时才出现)
inputdata-disabled''(条件成立时才出现)
inputdata-xh-field-input''
listdata-collapsed''(条件成立时才出现)
group-labeldata-collapsed''(条件成立时才出现)
branchdata-disabled''(条件成立时才出现)
branchdata-in-path''(条件成立时才出现)
branchdata-state'open' | 'closed'
branch-triggerdata-disabled''(条件成立时才出现)
branch-triggerdata-highlighted''(条件成立时才出现)
branch-triggerdata-in-path''(条件成立时才出现)
branch-triggerdata-pressed''(条件成立时才出现)
branch-triggerdata-state'open' | 'closed'
branch-triggerdata-tonemetaOf(v)?.tone
branch-triggerdata-valueitemValue(el)
branch-triggerdata-xh-collection-context'page'
branch-triggerdata-xh-collection-item''
branch-triggerdata-xh-collection-sizeprops.size
branch-textdata-xh-collection-slot'text'
branch-indicatordata-state'open' | 'closed'
branch-indicatordata-xh-collection-slot'suffix'
branch-contentdata-popout''
branch-contentdata-state'open' | 'closed'
linkdata-current''(条件成立时才出现)
linkdata-disabled''(条件成立时才出现)
linkdata-highlighted''(条件成立时才出现)
linkdata-pressed''(条件成立时才出现)
linkdata-tonemetaOf(v)?.tone
linkdata-valueitemValue(el)
linkdata-xh-collection-context'page'
linkdata-xh-collection-item''
linkdata-xh-collection-sizeprops.size
link-textdata-xh-collection-slot'text'
popout-positionerdata-hidden''(条件成立时才出现)
popout-positionerdata-placementplaced?.placement
popout-positionerdata-positioned''(条件成立时才出现)
popout-positionerdata-sizeprops.size
popout-positionerdata-state'open' | 'closed'
popout-positionerdata-toneprops.tone

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-side-nav-branch-indicator-sizebranch-indicator--xh-icon-size
block-size
inline-size
default--xh-control-indicator-sizeside-nav 的 branch-indicator 部件 --xh-icon-size、block-size、inline-size 覆盖槽。
--xh-side-nav-collapsed-wrootinline-sizecollapsed--xh-sider-collapsed-wside-nav 的 root 部件 inline-size 覆盖槽。
--xh-side-nav-empty-fgemptycolordefault--xh-fg-mutedside-nav 的 empty 部件 color 覆盖槽。
--xh-side-nav-empty-font-sizeemptyfont-sizedefault--xh-_side-nav-row-font-sizeside-nav 的 empty 部件 font-size 覆盖槽。
--xh-side-nav-empty-pxemptypadding-inlinedefault--xh-_side-nav-row-pxside-nav 的 empty 部件 padding-inline 覆盖槽。
--xh-side-nav-empty-pyemptypadding-blockdefault--xh-space-3side-nav 的 empty 部件 padding-block 覆盖槽。
--xh-side-nav-fgrootcolordefault--xh-fg-defaultside-nav 的 root 部件 color 覆盖槽。
--xh-side-nav-gapbranch
branch-content
group
group-list
list
root
gapdefault--xh-space-1side-nav 的 branch、branch-content、group、group-list、list、root 部件 gap 覆盖槽。
--xh-side-nav-group-label-pxgroup-labelpadding-inlinedefault--xh-_side-nav-row-pxside-nav 的 group-label 部件 padding-inline 覆盖槽。
--xh-side-nav-group-label-pygroup-labelpadding-blockdefault--xh-space-1side-nav 的 group-label 部件 padding-block 覆盖槽。
--xh-side-nav-icon-sizebranch-trigger
link
positioner
root
--xh-icon-sizedefault
is([data-part='root'], [data-part='positioner'])
size=lg
size=sm
--xh-_collection-glyph-size
--xh-glyph-size-lg
--xh-glyph-size-md
--xh-glyph-size-sm
side-nav 的 branch-trigger、link、positioner、root 部件 --xh-icon-size 覆盖槽。
--xh-side-nav-indentbranch-contentpadding-inline-startdefault--xh-space-4side-nav 的 branch-content 部件 padding-inline-start 覆盖槽。
--xh-side-nav-indicator-colorbranch-trigger
link
colorcurrent
disabled
error
highlighted
hover
is(:active, [data-pressed])
is(:focus-visible, [data-highlighted])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
xh-collection-context=page
xh-collection-slot=indicator
--xh-fg-brandside-nav 的 branch-trigger、link 部件 color 覆盖槽。
--xh-side-nav-input-autofill-bginputbox-shadow-webkit-autofill
autofill
--xh-bg-surfaceside-nav 的 input 部件 box-shadow 覆盖槽。
--xh-side-nav-input-autofill-fginput-webkit-text-fill-color-webkit-autofill
autofill
--xh-fg-defaultside-nav 的 input 部件 -webkit-text-fill-color 覆盖槽。
--xh-side-nav-input-font-sizeinputfont-sizedefault--xh-_side-nav-row-font-sizeside-nav 的 input 部件 font-size 覆盖槽。
--xh-side-nav-input-hinputblock-sizedefault--xh-_side-nav-input-hside-nav 的 input 部件 block-size 覆盖槽。
--xh-side-nav-input-pxinputpadding-inlinedefault--xh-_side-nav-row-pxside-nav 的 input 部件 padding-inline 覆盖槽。
--xh-side-nav-link-font-sizebranch-trigger
link
font-sizedefault--xh-_side-nav-row-font-sizeside-nav 的 branch-trigger、link 部件 font-size 覆盖槽。
--xh-side-nav-link-gapbranch-trigger
link
gapdefault--xh-_side-nav-row-gapside-nav 的 branch-trigger、link 部件 gap 覆盖槽。
--xh-side-nav-link-hbranch-trigger
link
min-block-sizedefault--xh-_side-nav-row-hside-nav 的 branch-trigger、link 部件 min-block-size 覆盖槽。
--xh-side-nav-link-pxbranch-trigger
link
padding-inlinedefault--xh-_side-nav-row-pxside-nav 的 branch-trigger、link 部件 padding-inline 覆盖槽。
--xh-side-nav-link-radiusbranch-trigger
link
border-radiusdefault--xh-shape-surfaceside-nav 的 branch-trigger、link 部件 border-radius 覆盖槽。
--xh-side-nav-prootpaddingdefault--xh-space-2side-nav 的 root 部件 padding 覆盖槽。
--xh-side-nav-placeholder-fginputcolorplaceholder
xh-field-input
--xh-fg-subtleside-nav 的 input 部件 color 覆盖槽。
--xh-side-nav-popout-bgbranch-contentbackgroundpopout--xh-bg-surfaceside-nav 的 branch-content 部件 background 覆盖槽。
--xh-side-nav-popout-borderbranch-contentborderpopout--xh-border-defaultside-nav 的 branch-content 部件 border 覆盖槽。
--xh-side-nav-popout-layerpositionerz-indexdefault--xh-_layerside-nav 的 positioner 部件 z-index 覆盖槽。
--xh-side-nav-popout-max-hbranch-contentmax-block-sizepopout--xh-overlay-menu-max-hside-nav 的 branch-content 部件 max-block-size 覆盖槽。
--xh-side-nav-popout-max-wbranch-contentmax-inline-sizepopout--xh-overlay-max-wside-nav 的 branch-content 部件 max-inline-size 覆盖槽。
--xh-side-nav-popout-min-wbranch-contentmin-inline-sizepopout--xh-overlay-menu-min-wside-nav 的 branch-content 部件 min-inline-size 覆盖槽。
--xh-side-nav-popout-pbranch-contentpaddingpopout--xh-space-1side-nav 的 branch-content 部件 padding 覆盖槽。
--xh-side-nav-popout-radiusbranch-contentborder-radiuspopout--xh-shape-overlayside-nav 的 branch-content 部件 border-radius 覆盖槽。
--xh-side-nav-popout-shadowbranch-contentbox-shadowpopout--xh-elevation-floatingside-nav 的 branch-content 部件 box-shadow 覆盖槽。
--xh-side-nav-row-bg-activebranch-trigger
link
background-colorcurrent
disabled
error
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
xh-collection-context=page
--xh-bg-brand-subtleside-nav 的 branch-trigger、link 部件 background-color 覆盖槽。
--xh-side-nav-row-bg-hoverbranch-trigger
link
background-colordisabled
error
highlighted
hover
is(:focus-visible, [data-highlighted])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
--xh-bg-subtleside-nav 的 branch-trigger、link 部件 background-color 覆盖槽。
--xh-side-nav-row-bg-in-pathbranch-trigger
link
background-colorin-path--xh-bg-subtleside-nav 的 branch-trigger、link 部件 background-color 覆盖槽。
--xh-side-nav-row-bg-pressedbranch-trigger
link
background-colordisabled
error
is(:active, [data-pressed])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
--xh-bg-subtle-hoverside-nav 的 branch-trigger、link 部件 background-color 覆盖槽。
--xh-side-nav-row-fgbranch-trigger
link
colordefault
disabled
error
highlighted
hover
in-path
is(:active, [data-pressed])
is(:focus-visible, [data-highlighted])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
currentColorside-nav 的 branch-trigger、link 部件 color 覆盖槽。
--xh-side-nav-row-fg-activebranch-trigger
link
colorcurrent
disabled
error
highlighted
hover
is(:active, [data-pressed])
is(:focus-visible, [data-highlighted])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
xh-collection-context=page
--xh-fg-on-brand-subtleside-nav 的 branch-trigger、link 部件 color 覆盖槽。
--xh-side-nav-row-fg-in-pathbranch-trigger
link
colorin-path--xh-side-nav-row-fgside-nav 的 branch-trigger、link 部件 color 覆盖槽。
--xh-side-nav-row-font-weight-activebranch-trigger
link
font-weightcurrent
disabled
error
highlighted
hover
is(:active, [data-pressed])
is(:focus-visible, [data-highlighted])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
xh-collection-context=page
--xh-font-weight-semiboldside-nav 的 branch-trigger、link 部件 font-weight 覆盖槽。
--xh-side-nav-search-dividerinputborder-block-enddefault--xh-material-solid-separatorside-nav 的 input 部件 border-block-end 覆盖槽。
--xh-side-nav-wrootinline-sizedefault--xh-sider-wside-nav 的 root 部件 inline-size 覆盖槽。

动效 ​

动效角色:按压 · 状态 · 切换 · 指示与换位 · 出现(见动效规范)。

共享关键帧 xh-overlay-pop-in · xh-pop-out 由 family/motion.css 提供,皮肤 @import 它,单独引入仍成立;color · inline-size · opacity · rotate 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

皮肤之外还有一段:退场由适配器的退场闸门把关,动画播完才真收起。

系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;只认物理方向的量乘 --xh-direction-sign 换向,按就近的 dir 走。

Released under The MIT License