컴포넌트
검색 트리거
아이콘, 단어, 단축키 칩이 한 버튼에 담긴 검색 입구예요.
- #arc
- #component
- #search
- #shortcut
- #command-palette
- #header
1280px
설치
이 명령 한 줄이면 필요한 파일과 패키지가 함께 설치돼요.
터미널터미널터미널bash
npx shadcn@latest add https://dsui.vercel.app/r/search-trigger.json파일
components/arc/search-trigger/search-trigger.module.csscomponents/arc/search-trigger/search-trigger.tsx
함께 오는 항목
search-trigger.module.csssearch-trigger.module.csssearch-trigger.module.csscss
/* The trigger opens a floating layer, so it never scales on press: Radix measures the anchor on pointerdown. */
.trigger { display: inline-flex; min-height: var(--control-height-md); align-items: center; gap: var(--space-2); border: 1px solid var(--border); border-radius: var(--radius-control); padding: 0 var(--space-3) 0 var(--space-4); background: var(--surface); color: var(--text-secondary); font: inherit; font-size: var(--label-md); font-weight: var(--label-weight); line-height: var(--leading-body); white-space: nowrap; cursor: pointer; -webkit-tap-highlight-color: transparent; transition: color var(--duration-fast) var(--ease-standard), background var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard); }
.trigger svg { flex: none; }
.trigger:disabled { background: var(--surface-muted); border-color: transparent; color: color-mix(in oklab, var(--foreground) 55%, transparent); cursor: not-allowed; }
.label { color: inherit; }
/* A key hint, not a control: it keeps the quiet well so it never competes with the word beside it. */
.kbd { display: inline-flex; min-width: var(--space-6); height: var(--space-6); align-items: center; justify-content: center; border-radius: var(--radius-pill); padding: 0 var(--space-2); background: var(--surface-muted); color: var(--foreground); font-family: inherit; font-size: var(--text-xs); font-weight: var(--label-weight); }
.sm { min-height: var(--control-height-sm); padding-inline: var(--space-2) var(--space-3); font-size: var(--label-sm); }
.compact { padding-inline: 0; justify-content: center; width: var(--control-height-md); }
.sm.compact { width: var(--control-height-sm); }
@media (hover: hover) and (pointer: fine) {
.trigger:hover:not(:disabled) { border-color: var(--foreground); color: var(--foreground); }
}
.trigger:active:not(:disabled) { background: var(--surface-muted); border-color: var(--foreground); color: var(--foreground); }
/* Pointers without hover never see the shortcut, and the chip only tells a keyboard user something they can act on. */
@media (hover: none) { .kbd { display: none; } }
@media (prefers-reduced-motion: reduce) { .trigger { transition: none; } }
search-trigger.tsxsearch-trigger.tsxsearch-trigger.tsxtsx
"use client";
import { forwardRef } from "react";
import type { ButtonHTMLAttributes } from "react";
import { playUiSound } from "../sound/play";
import { UiIcon } from "../theme/ui-icon";
import styles from "./search-trigger.module.css";
export interface SearchTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
/** The word on the control, and its accessible name when the label is hidden. Default "검색". */
label?: string;
/** The shortcut chip, e.g. "⌘K". Left out, no chip shows. */
shortcut?: string;
/** Keeps the icon only. The label stays the accessible name. */
compact?: boolean;
size?: "sm" | "md";
}
/**
* One control for the whole search entry point: icon, word and shortcut chip. It opens a dialog (a command palette),
* so it plays the open sound and says so with aria-haspopup; the chip is hidden from assistive tech because
* aria-keyshortcuts already carries the shortcut.
*/
export const SearchTrigger = forwardRef<HTMLButtonElement, SearchTriggerProps>(function SearchTrigger(
{ className, label = "검색", shortcut, compact = false, size = "md", onClick, ...props },
ref,
) {
const classes = [styles.trigger, styles[size], compact ? styles.compact : "", className].filter(Boolean).join(" ");
return (
<button
{...props}
ref={ref}
type="button"
className={classes}
aria-label={compact ? label : props["aria-label"]}
aria-haspopup="dialog"
aria-keyshortcuts={props["aria-keyshortcuts"] ?? (shortcut ? "Meta+K Control+K" : undefined)}
onClick={event => { playUiSound("open"); onClick?.(event); }}
>
<UiIcon iconRole="search" size={17} strokeWidth={1.75} aria-hidden="true" />
{compact ? null : <span className={styles.label}>{label}</span>}
{compact || !shortcut ? null : <kbd className={styles.kbd} aria-hidden="true">{shortcut}</kbd>}
</button>
);
});
SearchTrigger.displayName = "SearchTrigger";
export default SearchTrigger;