Skip to content

Commit 49156a3

Browse files
mudcubeclaude
andcommitted
fix: wrap SearchModal in container to prevent layout issues
- Wrapped component in fixed-position container with pointer-events: none - Container positioned at top-right, doesn't affect document flow - Re-enabled pointer events on children (trigger button and modal) - Prevents search trigger from taking up space and pushing content down Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent a03e58b commit 49156a3

1 file changed

Lines changed: 121 additions & 101 deletions

File tree

src/lib/components/SearchModal.svelte

Lines changed: 121 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -149,115 +149,135 @@
149149
});
150150
</script>
151151

152-
<!-- Trigger Button -->
153-
<button class="search-trigger" onclick={openModal} type="button" aria-label="Search documentation">
154-
<Search size={18} />
155-
<span class="search-trigger-text">Search...</span>
156-
<kbd class="search-trigger-kbd">
157-
<Command size={12} />
158-
<span>K</span>
159-
</kbd>
160-
</button>
161-
162-
<!-- Modal -->
163-
{#if isOpen}
164-
<div class="search-modal-overlay" onclick={closeModal}></div>
165-
<div
166-
class="search-modal"
167-
role="dialog"
168-
aria-modal="true"
169-
aria-labelledby="search-modal-title"
170-
aria-describedby="search-modal-description"
152+
<div class="search-container">
153+
<!-- Trigger Button -->
154+
<button
155+
class="search-trigger"
156+
onclick={openModal}
157+
type="button"
158+
aria-label="Search documentation"
171159
>
172-
<!-- Search Input -->
173-
<div class="search-modal-header">
174-
<Search size={20} class="search-modal-icon" aria-hidden="true" />
175-
<label for="search-modal-input" class="visually-hidden" id="search-modal-title"
176-
>Search documentation</label
177-
>
178-
<input
179-
id="search-modal-input"
180-
bind:value={query}
181-
class="search-modal-input"
182-
type="text"
183-
{placeholder}
184-
autocomplete="off"
185-
spellcheck="false"
186-
aria-describedby="search-modal-description"
187-
/>
188-
<button
189-
class="search-modal-close"
190-
onclick={closeModal}
191-
type="button"
192-
aria-label="Close search"
193-
>
194-
<X size={20} aria-hidden="true" />
195-
</button>
196-
</div>
197-
198-
<!-- Hidden description for screen readers -->
199-
<span id="search-modal-description" class="visually-hidden"
200-
>Use arrow keys to navigate results, enter to select, escape to close</span
160+
<Search size={18} />
161+
<span class="search-trigger-text">Search...</span>
162+
<kbd class="search-trigger-kbd">
163+
<Command size={12} />
164+
<span>K</span>
165+
</kbd>
166+
</button>
167+
168+
<!-- Modal -->
169+
{#if isOpen}
170+
<div class="search-modal-overlay" onclick={closeModal}></div>
171+
<div
172+
class="search-modal"
173+
role="dialog"
174+
aria-modal="true"
175+
aria-labelledby="search-modal-title"
176+
aria-describedby="search-modal-description"
201177
>
178+
<!-- Search Input -->
179+
<div class="search-modal-header">
180+
<Search size={20} class="search-modal-icon" aria-hidden="true" />
181+
<label for="search-modal-input" class="visually-hidden" id="search-modal-title"
182+
>Search documentation</label
183+
>
184+
<input
185+
id="search-modal-input"
186+
bind:value={query}
187+
class="search-modal-input"
188+
type="text"
189+
{placeholder}
190+
autocomplete="off"
191+
spellcheck="false"
192+
aria-describedby="search-modal-description"
193+
/>
194+
<button
195+
class="search-modal-close"
196+
onclick={closeModal}
197+
type="button"
198+
aria-label="Close search"
199+
>
200+
<X size={20} aria-hidden="true" />
201+
</button>
202+
</div>
202203

203-
<!-- Results -->
204-
<div class="search-modal-results" role="region" aria-live="polite" aria-atomic="false">
205-
{#if isLoading}
206-
<div class="search-modal-loading">Loading search index...</div>
207-
{:else if query.trim() && results.length === 0}
208-
<div class="search-modal-empty">
209-
<p>No results found for "{query}"</p>
210-
<p class="search-modal-empty-hint">Try a different search term</p>
211-
</div>
212-
{:else if results.length > 0}
213-
{#each results as result, index (result.id)}
214-
<button
215-
class="search-result {index === selectedIndex ? 'selected' : ''}"
216-
onclick={() => handleResultClick(result)}
217-
type="button"
218-
role="option"
219-
aria-selected={index === selectedIndex}
220-
aria-label="{result.title} in {result.section}"
221-
>
222-
<div class="search-result-content">
223-
<div class="search-result-section">{result.section}</div>
224-
<div class="search-result-title">
225-
{@html highlightMatches(result.title, query)}
226-
</div>
227-
{#if result.match.excerpt}
228-
<div class="search-result-excerpt">
229-
{@html highlightMatches(result.match.excerpt, query)}
204+
<!-- Hidden description for screen readers -->
205+
<span id="search-modal-description" class="visually-hidden"
206+
>Use arrow keys to navigate results, enter to select, escape to close</span
207+
>
208+
209+
<!-- Results -->
210+
<div class="search-modal-results" role="region" aria-live="polite" aria-atomic="false">
211+
{#if isLoading}
212+
<div class="search-modal-loading">Loading search index...</div>
213+
{:else if query.trim() && results.length === 0}
214+
<div class="search-modal-empty">
215+
<p>No results found for "{query}"</p>
216+
<p class="search-modal-empty-hint">Try a different search term</p>
217+
</div>
218+
{:else if results.length > 0}
219+
{#each results as result, index (result.id)}
220+
<button
221+
class="search-result {index === selectedIndex ? 'selected' : ''}"
222+
onclick={() => handleResultClick(result)}
223+
type="button"
224+
role="option"
225+
aria-selected={index === selectedIndex}
226+
aria-label="{result.title} in {result.section}"
227+
>
228+
<div class="search-result-content">
229+
<div class="search-result-section">{result.section}</div>
230+
<div class="search-result-title">
231+
{@html highlightMatches(result.title, query)}
230232
</div>
233+
{#if result.match.excerpt}
234+
<div class="search-result-excerpt">
235+
{@html highlightMatches(result.match.excerpt, query)}
236+
</div>
237+
{/if}
238+
</div>
239+
{#if index === selectedIndex}
240+
<CornerDownLeft size={16} class="search-result-enter-icon" aria-hidden="true" />
231241
{/if}
232-
</div>
233-
{#if index === selectedIndex}
234-
<CornerDownLeft size={16} class="search-result-enter-icon" aria-hidden="true" />
235-
{/if}
236-
</button>
237-
{/each}
238-
{/if}
239-
</div>
240-
241-
<!-- Footer with keyboard hints -->
242-
<div class="search-modal-footer">
243-
<div class="search-modal-hint">
244-
<kbd><ArrowUp size={12} /></kbd>
245-
<kbd><ArrowDown size={12} /></kbd>
246-
<span>Navigate</span>
247-
</div>
248-
<div class="search-modal-hint">
249-
<kbd><CornerDownLeft size={12} /></kbd>
250-
<span>Select</span>
242+
</button>
243+
{/each}
244+
{/if}
251245
</div>
252-
<div class="search-modal-hint">
253-
<kbd>ESC</kbd>
254-
<span>Close</span>
246+
247+
<!-- Footer with keyboard hints -->
248+
<div class="search-modal-footer">
249+
<div class="search-modal-hint">
250+
<kbd><ArrowUp size={12} /></kbd>
251+
<kbd><ArrowDown size={12} /></kbd>
252+
<span>Navigate</span>
253+
</div>
254+
<div class="search-modal-hint">
255+
<kbd><CornerDownLeft size={12} /></kbd>
256+
<span>Select</span>
257+
</div>
258+
<div class="search-modal-hint">
259+
<kbd>ESC</kbd>
260+
<span>Close</span>
261+
</div>
255262
</div>
256263
</div>
257-
</div>
258-
{/if}
264+
{/if}
265+
</div>
259266

260267
<style>
268+
/* Container - doesn't affect layout */
269+
.search-container {
270+
position: fixed;
271+
top: 0;
272+
right: 0;
273+
pointer-events: none;
274+
z-index: 100;
275+
}
276+
277+
.search-container > * {
278+
pointer-events: auto;
279+
}
280+
261281
/* Visually hidden but accessible to screen readers */
262282
.visually-hidden {
263283
position: absolute;
@@ -273,9 +293,10 @@
273293
274294
/* Trigger Button */
275295
.search-trigger {
276-
position: fixed;
296+
position: relative;
277297
top: 20px;
278298
right: 20px;
299+
margin-left: auto;
279300
display: flex;
280301
align-items: center;
281302
gap: var(--docs-spacing-sm, 0.5rem);
@@ -288,7 +309,6 @@
288309
transition: all 0.2s ease;
289310
font-size: 0.875rem;
290311
min-width: 240px;
291-
z-index: 100;
292312
}
293313
294314
.search-trigger:hover {

0 commit comments

Comments
 (0)