01 / 20
All 20 in 20 CSS Empty States
- 01No Search Results State
- 02First-Time Onboarding State
- 03Empty Shopping Cart State
- 04Inbox Zero / All Caught Up State
- 05Empty Data Table / No Rows State
- 06Filtered List No Matches State
- 07Empty Dashboard / No Analytics Data
- 08500 Server Error Page Layout
- 09Empty Wishlist / Favorites State
- 10Empty Notification Center Flyout
- 11Failed to Load / Connection Error State
- 12Offline / No Internet Connection State
- 13Permission Denied / Restricted Access State
- 14404 Page Not Found Layout
- 15Deleted or Archived Items State
- 16Skeleton Loading to Empty State Transition
- 17Accessible Empty State (ARIA Live)
- 18Pure CSS Illustrated Empty State
- 19Dark Mode Compatible Empty State
- 20Inline / Micro Empty State Component
No Search Results State
A search that returns nothing inside a real issue tracker: filter chips above the results, the query echoed back in monospace, and one primary recovery that removes the filter most likely to be the problem. Dropping a chip swaps the empty state for real rows, so the demo shows both halves of the state machine rather than a poster of the sad half.
Nucleo: 44,000+ SVG icons in five families · All Icons Bundle $149
Nucleo · Affiliate link
The code
<div class="est-01">
<div class="est-01__shell">
<nav class="est-01__rail" aria-label="Workspace">
<span class="est-01__mark" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M5 17.5 12 4l7 13.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M8.4 17.5h7.2" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
</span>
<button class="est-01__ri est-01__ri--on" type="button" aria-label="Issues" aria-current="page">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><circle cx="12" cy="12" r="7.5" stroke="currentColor" stroke-width="1.7"/><path d="M12 8.4v4.2M12 15.5h.01" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
</button>
<button class="est-01__ri" type="button" aria-label="Pull requests">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><circle cx="7" cy="6.5" r="2.3" stroke="currentColor" stroke-width="1.7"/><circle cx="7" cy="17.5" r="2.3" stroke="currentColor" stroke-width="1.7"/><circle cx="17" cy="17.5" r="2.3" stroke="currentColor" stroke-width="1.7"/><path d="M7 8.8v6.4M9.3 6.5h5.2a2.5 2.5 0 0 1 2.5 2.5v6.2" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
</button>
<button class="est-01__ri" type="button" aria-label="Deployments">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M4 15.5 12 4l8 11.5" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/><path d="M4.5 19.5h15" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
</button>
<button class="est-01__ri" type="button" aria-label="Insights">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M4 19V6M20 19H4M8 15.5V11M12.5 15.5V8M17 15.5v-3" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
</button>
<span class="est-01__grow"></span>
<span class="est-01__me" aria-hidden="true">AR</span>
</nav>
<div class="est-01__main">
<header class="est-01__top">
<div class="est-01__field">
<svg class="est-01__mag" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="11" cy="11" r="6.2" stroke="currentColor" stroke-width="1.8"/><path d="m15.8 15.8 3.7 3.7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
<span class="est-01__q" id="est-01-query">is:open label:regression owner:platform</span>
<button class="est-01__x" type="button" data-act="reset" aria-label="Clear search">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
</button>
</div>
<div class="est-01__tabs" role="tablist" aria-label="Search scope">
<button class="est-01__tab est-01__tab--on" type="button" role="tab" aria-selected="true">Issues</button>
<button class="est-01__tab" type="button" role="tab" aria-selected="false">Pull requests</button>
<button class="est-01__tab" type="button" role="tab" aria-selected="false">Discussions</button>
</div>
</header>
<div class="est-01__chips" id="est-01-chips">
<button class="est-01__chip" type="button" data-drop="label:regression">label:regression<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
<button class="est-01__chip" type="button" data-drop="owner:platform">owner:platform<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
<button class="est-01__chip" type="button" data-drop="is:open">is:open<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
</div>
<section class="est-01__body" aria-live="polite" aria-atomic="true">
<div class="est-01__empty" id="est-01-empty">
<span class="est-01__glyph" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><circle cx="10.5" cy="10.5" r="6.4" stroke="currentColor" stroke-width="1.6"/><path d="m15.4 15.4 4.1 4.1" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/><path d="M8 10.5h5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
</span>
<h1 class="est-01__h">No issues match all three filters</h1>
<p class="est-01__p">Platform has nothing open with that label.</p>
<div class="est-01__acts">
<button class="est-01__act est-01__act--pri" type="button" data-drop="label:regression">Drop label:regression</button>
<button class="est-01__act" type="button" data-act="reset">Search every repository</button>
</div>
</div>
<ol class="est-01__list" id="est-01-list" hidden>
<li class="est-01__row">
<span class="est-01__dot est-01__dot--open" aria-hidden="true"></span>
<span class="est-01__rmain"><span class="est-01__rt">Retry storm when the queue drains mid-deploy</span><span class="est-01__rm">platform/edge-router · #4821 · opened by dcheng</span></span>
<span class="est-01__pill">needs triage</span>
</li>
<li class="est-01__row">
<span class="est-01__dot est-01__dot--open" aria-hidden="true"></span>
<span class="est-01__rmain"><span class="est-01__rt">Token refresh drops the websocket session</span><span class="est-01__rm">platform/auth · #4804 · opened by mira.k</span></span>
<span class="est-01__pill est-01__pill--alt">in review</span>
</li>
<li class="est-01__row">
<span class="est-01__dot" aria-hidden="true"></span>
<span class="est-01__rmain"><span class="est-01__rt">Cold start regression on the image pipeline</span><span class="est-01__rm">platform/media · #4790 · opened by t.oyelaran</span></span>
<span class="est-01__pill est-01__pill--done">closed</span>
</li>
</ol>
</section>
</div>
</div>
</div><div class="est-01">
<div class="est-01__shell">
<nav class="est-01__rail" aria-label="Workspace">
<span class="est-01__mark" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M5 17.5 12 4l7 13.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M8.4 17.5h7.2" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
</span>
<button class="est-01__ri est-01__ri--on" type="button" aria-label="Issues" aria-current="page">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><circle cx="12" cy="12" r="7.5" stroke="currentColor" stroke-width="1.7"/><path d="M12 8.4v4.2M12 15.5h.01" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
</button>
<button class="est-01__ri" type="button" aria-label="Pull requests">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><circle cx="7" cy="6.5" r="2.3" stroke="currentColor" stroke-width="1.7"/><circle cx="7" cy="17.5" r="2.3" stroke="currentColor" stroke-width="1.7"/><circle cx="17" cy="17.5" r="2.3" stroke="currentColor" stroke-width="1.7"/><path d="M7 8.8v6.4M9.3 6.5h5.2a2.5 2.5 0 0 1 2.5 2.5v6.2" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
</button>
<button class="est-01__ri" type="button" aria-label="Deployments">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M4 15.5 12 4l8 11.5" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/><path d="M4.5 19.5h15" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
</button>
<button class="est-01__ri" type="button" aria-label="Insights">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M4 19V6M20 19H4M8 15.5V11M12.5 15.5V8M17 15.5v-3" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
</button>
<span class="est-01__grow"></span>
<span class="est-01__me" aria-hidden="true">AR</span>
</nav>
<div class="est-01__main">
<header class="est-01__top">
<div class="est-01__field">
<svg class="est-01__mag" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="11" cy="11" r="6.2" stroke="currentColor" stroke-width="1.8"/><path d="m15.8 15.8 3.7 3.7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
<span class="est-01__q" id="est-01-query">is:open label:regression owner:platform</span>
<button class="est-01__x" type="button" data-act="reset" aria-label="Clear search">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
</button>
</div>
<div class="est-01__tabs" role="tablist" aria-label="Search scope">
<button class="est-01__tab est-01__tab--on" type="button" role="tab" aria-selected="true">Issues</button>
<button class="est-01__tab" type="button" role="tab" aria-selected="false">Pull requests</button>
<button class="est-01__tab" type="button" role="tab" aria-selected="false">Discussions</button>
</div>
</header>
<div class="est-01__chips" id="est-01-chips">
<button class="est-01__chip" type="button" data-drop="label:regression">label:regression<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
<button class="est-01__chip" type="button" data-drop="owner:platform">owner:platform<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
<button class="est-01__chip" type="button" data-drop="is:open">is:open<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
</div>
<section class="est-01__body" aria-live="polite" aria-atomic="true">
<div class="est-01__empty" id="est-01-empty">
<span class="est-01__glyph" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><circle cx="10.5" cy="10.5" r="6.4" stroke="currentColor" stroke-width="1.6"/><path d="m15.4 15.4 4.1 4.1" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/><path d="M8 10.5h5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
</span>
<h1 class="est-01__h">No issues match all three filters</h1>
<p class="est-01__p">Platform has nothing open with that label.</p>
<div class="est-01__acts">
<button class="est-01__act est-01__act--pri" type="button" data-drop="label:regression">Drop label:regression</button>
<button class="est-01__act" type="button" data-act="reset">Search every repository</button>
</div>
</div>
<ol class="est-01__list" id="est-01-list" hidden>
<li class="est-01__row">
<span class="est-01__dot est-01__dot--open" aria-hidden="true"></span>
<span class="est-01__rmain"><span class="est-01__rt">Retry storm when the queue drains mid-deploy</span><span class="est-01__rm">platform/edge-router · #4821 · opened by dcheng</span></span>
<span class="est-01__pill">needs triage</span>
</li>
<li class="est-01__row">
<span class="est-01__dot est-01__dot--open" aria-hidden="true"></span>
<span class="est-01__rmain"><span class="est-01__rt">Token refresh drops the websocket session</span><span class="est-01__rm">platform/auth · #4804 · opened by mira.k</span></span>
<span class="est-01__pill est-01__pill--alt">in review</span>
</li>
<li class="est-01__row">
<span class="est-01__dot" aria-hidden="true"></span>
<span class="est-01__rmain"><span class="est-01__rt">Cold start regression on the image pipeline</span><span class="est-01__rm">platform/media · #4790 · opened by t.oyelaran</span></span>
<span class="est-01__pill est-01__pill--done">closed</span>
</li>
</ol>
</section>
</div>
</div>
</div>@import url('https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap');
.est-01 {
--bg: #0b0c0f;
--panel: #12141a;
--panel-2: #171a21;
--line: #22262f;
--line-2: #2c313c;
--text: #eef0f5;
--muted: #9aa1b1;
--faint: #6b7383;
--accent: #7aa2ff;
--open: #4ade80;
--warn: #f5b661;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
box-sizing: border-box;
background: var(--bg);
color: var(--text);
color-scheme: dark;
font-synthesis: none;
font-family: 'Geist',ui-sans-serif,system-ui,-apple-system,sans-serif;
-webkit-font-smoothing: antialiased;
}
.est-01 *,
.est-01 *::before,
.est-01 *::after {
box-sizing: border-box;
}
.est-01 [hidden] {
display: none !important;
}
@supports (color: oklch(0.7 0.1 300)) {
.est-01 {
--bg: oklch(0.16 0.011 265);
--panel: oklch(0.203 0.013 265);
--panel-2: oklch(0.235 0.015 265);
--line: oklch(0.29 0.014 265);
--line-2: oklch(0.345 0.016 265);
--text: oklch(0.965 0.004 265);
--muted: oklch(0.735 0.021 265);
--faint: oklch(0.585 0.021 265);
--accent: oklch(0.775 0.115 262);
--open: oklch(0.82 0.17 152);
--warn: oklch(0.82 0.11 72);
}
}
.est-01__shell {
min-height: 100vh;
min-height: 100svh;
display: grid;
grid-template-columns: 4.25rem minmax(0,1fr);
}
.est-01__rail {
display: flex;
flex-direction: column;
align-items: center;
gap: .35rem;
padding: 1rem .75rem 1.25rem;
border-inline-end: 1px solid var(--line);
background: linear-gradient(180deg,var(--panel),var(--bg));
}
.est-01__mark {
inline-size: 2.25rem;
block-size: 2.25rem;
display: grid;
place-items: center;
margin-block-end: .75rem;
border-radius: 11px;
color: var(--bg);
background: var(--text);
}
.est-01__mark svg {
inline-size: 1.2rem;
block-size: 1.2rem;
}
.est-01__ri {
inline-size: 2.5rem;
block-size: 2.5rem;
display: grid;
place-items: center;
cursor: pointer;
background: transparent;
border: 1px solid transparent;
border-radius: 11px;
color: var(--faint);
transition: color .18s, background .18s, border-color .18s;
}
.est-01__ri svg {
inline-size: 1.2rem;
block-size: 1.2rem;
}
.est-01__ri:hover {
color: var(--text);
background: var(--panel-2);
}
.est-01__ri--on {
color: var(--text);
background: var(--panel-2);
border-color: var(--line-2);
}
.est-01__ri:focus-visible,
.est-01__x:focus-visible,
.est-01__chip:focus-visible,
.est-01__act:focus-visible,
.est-01__tab:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.est-01__grow {
flex: 1 1 auto;
}
.est-01__me {
inline-size: 2rem;
block-size: 2rem;
display: grid;
place-items: center;
border-radius: 50%;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .68rem;
letter-spacing: .04em;
color: var(--text);
background: var(--panel-2);
border: 1px solid var(--line-2);
}
.est-01__main {
min-inline-size: 0;
display: grid;
grid-template-rows: auto auto minmax(0,1fr);
align-content: start;
}
.est-01__top {
display: flex;
flex-wrap: wrap;
gap: .9rem 1.5rem;
align-items: center;
justify-content: space-between;
padding: 1rem clamp(1rem,3vw,2rem);
border-block-end: 1px solid var(--line);
background: color-mix(in oklab, var(--panel) 70%, transparent);
backdrop-filter: blur(8px);
}
.est-01__field {
flex: 1 1 22rem;
min-inline-size: 0;
display: flex;
align-items: center;
gap: .6rem;
padding: .6rem .7rem .6rem .8rem;
background: var(--panel-2);
border: 1px solid var(--line-2);
border-radius: 12px;
box-shadow: inset 0 1px 0 color-mix(in oklab, #fff 5%, transparent);
}
.est-01__mag {
inline-size: 1.05rem;
block-size: 1.05rem;
flex: none;
color: var(--faint);
}
.est-01__q {
flex: 1 1 auto;
min-inline-size: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .82rem;
letter-spacing: -.01em;
color: var(--text);
}
.est-01__x {
inline-size: 1.6rem;
block-size: 1.6rem;
flex: none;
display: grid;
place-items: center;
cursor: pointer;
color: var(--faint);
background: transparent;
border: 0;
border-radius: 7px;
transition: color .16s, background .16s;
}
.est-01__x svg {
inline-size: .85rem;
block-size: .85rem;
}
.est-01__x:hover {
color: var(--text);
background: var(--line-2);
}
.est-01__tabs {
display: flex;
gap: .15rem;
padding: .2rem;
background: var(--panel-2);
border: 1px solid var(--line);
border-radius: 11px;
}
.est-01__tab {
padding: .42rem .7rem;
font: inherit;
font-size: .8rem;
font-weight: 500;
cursor: pointer;
white-space: nowrap;
color: var(--muted);
background: transparent;
border: 0;
border-radius: 8px;
transition: color .16s, background .16s;
}
.est-01__tab:hover {
color: var(--text);
}
.est-01__tab--on {
color: var(--text);
background: var(--line-2);
box-shadow: 0 1px 2px rgba(0,0,0,.35);
}
.est-01__chips {
display: flex;
flex-wrap: wrap;
gap: .4rem;
padding: .75rem clamp(1rem,3vw,2rem);
border-block-end: 1px solid var(--line);
}
.est-01__chip {
display: inline-flex;
align-items: center;
gap: .4rem;
padding: .34rem .5rem .34rem .6rem;
cursor: pointer;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .72rem;
letter-spacing: -.01em;
color: var(--muted);
background: var(--panel);
border: 1px solid var(--line-2);
border-radius: 8px;
transition: color .16s, border-color .16s, background .16s, opacity .2s, scale .2s;
}
.est-01__chip svg {
inline-size: .6rem;
block-size: .6rem;
opacity: .65;
}
.est-01__chip:hover {
color: var(--text);
background: var(--panel-2);
border-color: var(--accent);
}
.est-01__chip[data-gone] {
opacity: 0;
scale: .9;
pointer-events: none;
}
.est-01__body {
min-block-size: 0;
padding: clamp(1rem,3vw,2rem);
display: grid;
align-content: start;
}
.est-01__empty {
justify-self: center;
align-self: start;
margin-block: clamp(1.5rem,7vh,5rem);
inline-size: min(30rem,100%);
display: grid;
justify-items: center;
text-align: center;
gap: .55rem;
animation: est-01-in .5s cubic-bezier(.2,.7,.3,1) both;
}
@keyframes est-01-in {
from {
opacity: 0;
translate: 0 8px;
}
to {
opacity: 1;
translate: 0 0;
}
}
.est-01__glyph {
position: relative;
inline-size: 5.5rem;
block-size: 5.5rem;
display: grid;
place-items: center;
margin-block-end: .6rem;
border: 1px solid var(--line-2);
border-radius: 18px;
color: var(--muted);
overflow: hidden;
background: radial-gradient(circle at 50% 45%, color-mix(in oklab, var(--accent) 12%, transparent), transparent 62%), var(--panel-2);
}
.est-01__glyph::before {
content: '';
position: absolute;
inset: 0;
background-image: linear-gradient(var(--line) 1px,transparent 1px),linear-gradient(90deg,var(--line) 1px,transparent 1px);
background-size: 11px 11px;
opacity: .55;
mask-image: radial-gradient(circle at 50% 50%, #000 45%, transparent 78%);
}
.est-01__glyph::after {
content: '';
position: absolute;
inset-block: 0;
inline-size: 38%;
background: linear-gradient(90deg,transparent,color-mix(in oklab, var(--accent) 18%, transparent),transparent);
animation: est-01-sweep 5.5s ease-in-out infinite;
}
@keyframes est-01-sweep {
0%,
100% {
translate: -140% 0;
}
50% {
translate: 280% 0;
}
}
.est-01__glyph svg {
position: relative;
inline-size: 1.85rem;
block-size: 1.85rem;
}
.est-01__h {
margin: 0;
font-size: clamp(1.1rem,2.4vw,1.35rem);
font-weight: 600;
letter-spacing: -.025em;
line-height: 1.25;
text-wrap: balance;
}
.est-01__p {
margin: 0;
font-size: .9rem;
line-height: 1.55;
color: var(--muted);
text-wrap: pretty;
}
.est-01__acts {
display: flex;
flex-wrap: wrap;
gap: .5rem;
justify-content: center;
margin-block-start: .85rem;
}
.est-01__act {
min-block-size: 2.75rem;
padding: .6rem 1rem;
font: inherit;
font-size: .85rem;
font-weight: 500;
cursor: pointer;
color: var(--text);
background: var(--panel-2);
border: 1px solid var(--line-2);
border-radius: 11px;
transition: translate .16s, background .16s, border-color .16s;
}
.est-01__act:hover {
translate: 0 -1px;
background: var(--line-2);
}
.est-01__act--pri {
color: #0a0e1a;
background: var(--accent);
border-color: transparent;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .8rem;
letter-spacing: -.01em;
}
.est-01__act--pri:hover {
background: color-mix(in oklab, var(--accent) 88%, #fff);
}
.est-01__list {
margin: 0;
padding: 0;
list-style: none;
display: grid;
gap: .5rem;
inline-size: min(52rem,100%);
justify-self: center;
}
.est-01__row {
display: grid;
grid-template-columns: auto minmax(0,1fr) auto;
gap: .25rem .75rem;
align-items: center;
padding: .85rem 1rem;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 13px;
animation: est-01-in .45s cubic-bezier(.2,.7,.3,1) both;
}
.est-01__row:nth-child(2) {
animation-delay: .06s;
}
.est-01__row:nth-child(3) {
animation-delay: .12s;
}
.est-01__row:hover {
border-color: var(--line-2);
background: var(--panel-2);
}
.est-01__dot {
inline-size: .5rem;
block-size: .5rem;
border-radius: 50%;
background: var(--faint);
}
.est-01__dot--open {
background: var(--open);
box-shadow: 0 0 0 3px color-mix(in oklab, var(--open) 18%, transparent);
}
.est-01__rmain {
min-inline-size: 0;
display: grid;
gap: .2rem;
}
.est-01__rt {
font-size: .9rem;
font-weight: 500;
letter-spacing: -.012em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.est-01__rm {
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .7rem;
color: var(--faint);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.est-01__pill {
padding: .24rem .5rem;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .66rem;
letter-spacing: .02em;
white-space: nowrap;
color: var(--warn);
background: color-mix(in oklab, var(--warn) 12%, transparent);
border: 1px solid color-mix(in oklab, var(--warn) 30%, transparent);
border-radius: 6px;
}
.est-01__pill--alt {
color: var(--accent);
background: color-mix(in oklab, var(--accent) 12%, transparent);
border-color: color-mix(in oklab, var(--accent) 30%, transparent);
}
.est-01__pill--done {
color: var(--faint);
background: var(--panel-2);
border-color: var(--line-2);
}
@media (max-width: 640px) {
.est-01__shell {
grid-template-columns: 1fr;
}
.est-01__rail {
flex-direction: row;
border-inline-end: 0;
border-block-end: 1px solid var(--line);
}
.est-01__mark {
margin: 0 .5rem 0 0;
}
.est-01__pill {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.est-01 *,
.est-01 *::before,
.est-01 *::after {
animation: none !important;
transition: none !important;
}
}
@media (forced-colors: active) {
.est-01__glyph,
.est-01__row,
.est-01__field,
.est-01__act {
border-color: CanvasText;
}
}@import url('https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap');
.est-01 {
--bg: #0b0c0f;
--panel: #12141a;
--panel-2: #171a21;
--line: #22262f;
--line-2: #2c313c;
--text: #eef0f5;
--muted: #9aa1b1;
--faint: #6b7383;
--accent: #7aa2ff;
--open: #4ade80;
--warn: #f5b661;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
box-sizing: border-box;
background: var(--bg);
color: var(--text);
color-scheme: dark;
font-synthesis: none;
font-family: 'Geist',ui-sans-serif,system-ui,-apple-system,sans-serif;
-webkit-font-smoothing: antialiased;
}
.est-01 *,
.est-01 *::before,
.est-01 *::after {
box-sizing: border-box;
}
.est-01 [hidden] {
display: none !important;
}
@supports (color: oklch(0.7 0.1 300)) {
.est-01 {
--bg: oklch(0.16 0.011 265);
--panel: oklch(0.203 0.013 265);
--panel-2: oklch(0.235 0.015 265);
--line: oklch(0.29 0.014 265);
--line-2: oklch(0.345 0.016 265);
--text: oklch(0.965 0.004 265);
--muted: oklch(0.735 0.021 265);
--faint: oklch(0.585 0.021 265);
--accent: oklch(0.775 0.115 262);
--open: oklch(0.82 0.17 152);
--warn: oklch(0.82 0.11 72);
}
}
.est-01__shell {
min-height: 100vh;
min-height: 100svh;
display: grid;
grid-template-columns: 4.25rem minmax(0,1fr);
}
.est-01__rail {
display: flex;
flex-direction: column;
align-items: center;
gap: .35rem;
padding: 1rem .75rem 1.25rem;
border-inline-end: 1px solid var(--line);
background: linear-gradient(180deg,var(--panel),var(--bg));
}
.est-01__mark {
inline-size: 2.25rem;
block-size: 2.25rem;
display: grid;
place-items: center;
margin-block-end: .75rem;
border-radius: 11px;
color: var(--bg);
background: var(--text);
}
.est-01__mark svg {
inline-size: 1.2rem;
block-size: 1.2rem;
}
.est-01__ri {
inline-size: 2.5rem;
block-size: 2.5rem;
display: grid;
place-items: center;
cursor: pointer;
background: transparent;
border: 1px solid transparent;
border-radius: 11px;
color: var(--faint);
transition: color .18s, background .18s, border-color .18s;
}
.est-01__ri svg {
inline-size: 1.2rem;
block-size: 1.2rem;
}
.est-01__ri:hover {
color: var(--text);
background: var(--panel-2);
}
.est-01__ri--on {
color: var(--text);
background: var(--panel-2);
border-color: var(--line-2);
}
.est-01__ri:focus-visible,
.est-01__x:focus-visible,
.est-01__chip:focus-visible,
.est-01__act:focus-visible,
.est-01__tab:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.est-01__grow {
flex: 1 1 auto;
}
.est-01__me {
inline-size: 2rem;
block-size: 2rem;
display: grid;
place-items: center;
border-radius: 50%;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .68rem;
letter-spacing: .04em;
color: var(--text);
background: var(--panel-2);
border: 1px solid var(--line-2);
}
.est-01__main {
min-inline-size: 0;
display: grid;
grid-template-rows: auto auto minmax(0,1fr);
align-content: start;
}
.est-01__top {
display: flex;
flex-wrap: wrap;
gap: .9rem 1.5rem;
align-items: center;
justify-content: space-between;
padding: 1rem clamp(1rem,3vw,2rem);
border-block-end: 1px solid var(--line);
background: color-mix(in oklab, var(--panel) 70%, transparent);
backdrop-filter: blur(8px);
}
.est-01__field {
flex: 1 1 22rem;
min-inline-size: 0;
display: flex;
align-items: center;
gap: .6rem;
padding: .6rem .7rem .6rem .8rem;
background: var(--panel-2);
border: 1px solid var(--line-2);
border-radius: 12px;
box-shadow: inset 0 1px 0 color-mix(in oklab, #fff 5%, transparent);
}
.est-01__mag {
inline-size: 1.05rem;
block-size: 1.05rem;
flex: none;
color: var(--faint);
}
.est-01__q {
flex: 1 1 auto;
min-inline-size: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .82rem;
letter-spacing: -.01em;
color: var(--text);
}
.est-01__x {
inline-size: 1.6rem;
block-size: 1.6rem;
flex: none;
display: grid;
place-items: center;
cursor: pointer;
color: var(--faint);
background: transparent;
border: 0;
border-radius: 7px;
transition: color .16s, background .16s;
}
.est-01__x svg {
inline-size: .85rem;
block-size: .85rem;
}
.est-01__x:hover {
color: var(--text);
background: var(--line-2);
}
.est-01__tabs {
display: flex;
gap: .15rem;
padding: .2rem;
background: var(--panel-2);
border: 1px solid var(--line);
border-radius: 11px;
}
.est-01__tab {
padding: .42rem .7rem;
font: inherit;
font-size: .8rem;
font-weight: 500;
cursor: pointer;
white-space: nowrap;
color: var(--muted);
background: transparent;
border: 0;
border-radius: 8px;
transition: color .16s, background .16s;
}
.est-01__tab:hover {
color: var(--text);
}
.est-01__tab--on {
color: var(--text);
background: var(--line-2);
box-shadow: 0 1px 2px rgba(0,0,0,.35);
}
.est-01__chips {
display: flex;
flex-wrap: wrap;
gap: .4rem;
padding: .75rem clamp(1rem,3vw,2rem);
border-block-end: 1px solid var(--line);
}
.est-01__chip {
display: inline-flex;
align-items: center;
gap: .4rem;
padding: .34rem .5rem .34rem .6rem;
cursor: pointer;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .72rem;
letter-spacing: -.01em;
color: var(--muted);
background: var(--panel);
border: 1px solid var(--line-2);
border-radius: 8px;
transition: color .16s, border-color .16s, background .16s, opacity .2s, scale .2s;
}
.est-01__chip svg {
inline-size: .6rem;
block-size: .6rem;
opacity: .65;
}
.est-01__chip:hover {
color: var(--text);
background: var(--panel-2);
border-color: var(--accent);
}
.est-01__chip[data-gone] {
opacity: 0;
scale: .9;
pointer-events: none;
}
.est-01__body {
min-block-size: 0;
padding: clamp(1rem,3vw,2rem);
display: grid;
align-content: start;
}
.est-01__empty {
justify-self: center;
align-self: start;
margin-block: clamp(1.5rem,7vh,5rem);
inline-size: min(30rem,100%);
display: grid;
justify-items: center;
text-align: center;
gap: .55rem;
animation: est-01-in .5s cubic-bezier(.2,.7,.3,1) both;
}
@keyframes est-01-in {
from {
opacity: 0;
translate: 0 8px;
}
to {
opacity: 1;
translate: 0 0;
}
}
.est-01__glyph {
position: relative;
inline-size: 5.5rem;
block-size: 5.5rem;
display: grid;
place-items: center;
margin-block-end: .6rem;
border: 1px solid var(--line-2);
border-radius: 18px;
color: var(--muted);
overflow: hidden;
background: radial-gradient(circle at 50% 45%, color-mix(in oklab, var(--accent) 12%, transparent), transparent 62%), var(--panel-2);
}
.est-01__glyph::before {
content: '';
position: absolute;
inset: 0;
background-image: linear-gradient(var(--line) 1px,transparent 1px),linear-gradient(90deg,var(--line) 1px,transparent 1px);
background-size: 11px 11px;
opacity: .55;
mask-image: radial-gradient(circle at 50% 50%, #000 45%, transparent 78%);
}
.est-01__glyph::after {
content: '';
position: absolute;
inset-block: 0;
inline-size: 38%;
background: linear-gradient(90deg,transparent,color-mix(in oklab, var(--accent) 18%, transparent),transparent);
animation: est-01-sweep 5.5s ease-in-out infinite;
}
@keyframes est-01-sweep {
0%,
100% {
translate: -140% 0;
}
50% {
translate: 280% 0;
}
}
.est-01__glyph svg {
position: relative;
inline-size: 1.85rem;
block-size: 1.85rem;
}
.est-01__h {
margin: 0;
font-size: clamp(1.1rem,2.4vw,1.35rem);
font-weight: 600;
letter-spacing: -.025em;
line-height: 1.25;
text-wrap: balance;
}
.est-01__p {
margin: 0;
font-size: .9rem;
line-height: 1.55;
color: var(--muted);
text-wrap: pretty;
}
.est-01__acts {
display: flex;
flex-wrap: wrap;
gap: .5rem;
justify-content: center;
margin-block-start: .85rem;
}
.est-01__act {
min-block-size: 2.75rem;
padding: .6rem 1rem;
font: inherit;
font-size: .85rem;
font-weight: 500;
cursor: pointer;
color: var(--text);
background: var(--panel-2);
border: 1px solid var(--line-2);
border-radius: 11px;
transition: translate .16s, background .16s, border-color .16s;
}
.est-01__act:hover {
translate: 0 -1px;
background: var(--line-2);
}
.est-01__act--pri {
color: #0a0e1a;
background: var(--accent);
border-color: transparent;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .8rem;
letter-spacing: -.01em;
}
.est-01__act--pri:hover {
background: color-mix(in oklab, var(--accent) 88%, #fff);
}
.est-01__list {
margin: 0;
padding: 0;
list-style: none;
display: grid;
gap: .5rem;
inline-size: min(52rem,100%);
justify-self: center;
}
.est-01__row {
display: grid;
grid-template-columns: auto minmax(0,1fr) auto;
gap: .25rem .75rem;
align-items: center;
padding: .85rem 1rem;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 13px;
animation: est-01-in .45s cubic-bezier(.2,.7,.3,1) both;
}
.est-01__row:nth-child(2) {
animation-delay: .06s;
}
.est-01__row:nth-child(3) {
animation-delay: .12s;
}
.est-01__row:hover {
border-color: var(--line-2);
background: var(--panel-2);
}
.est-01__dot {
inline-size: .5rem;
block-size: .5rem;
border-radius: 50%;
background: var(--faint);
}
.est-01__dot--open {
background: var(--open);
box-shadow: 0 0 0 3px color-mix(in oklab, var(--open) 18%, transparent);
}
.est-01__rmain {
min-inline-size: 0;
display: grid;
gap: .2rem;
}
.est-01__rt {
font-size: .9rem;
font-weight: 500;
letter-spacing: -.012em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.est-01__rm {
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .7rem;
color: var(--faint);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.est-01__pill {
padding: .24rem .5rem;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .66rem;
letter-spacing: .02em;
white-space: nowrap;
color: var(--warn);
background: color-mix(in oklab, var(--warn) 12%, transparent);
border: 1px solid color-mix(in oklab, var(--warn) 30%, transparent);
border-radius: 6px;
}
.est-01__pill--alt {
color: var(--accent);
background: color-mix(in oklab, var(--accent) 12%, transparent);
border-color: color-mix(in oklab, var(--accent) 30%, transparent);
}
.est-01__pill--done {
color: var(--faint);
background: var(--panel-2);
border-color: var(--line-2);
}
@media (max-width: 640px) {
.est-01__shell {
grid-template-columns: 1fr;
}
.est-01__rail {
flex-direction: row;
border-inline-end: 0;
border-block-end: 1px solid var(--line);
}
.est-01__mark {
margin: 0 .5rem 0 0;
}
.est-01__pill {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.est-01 *,
.est-01 *::before,
.est-01 *::after {
animation: none !important;
transition: none !important;
}
}
@media (forced-colors: active) {
.est-01__glyph,
.est-01__row,
.est-01__field,
.est-01__act {
border-color: CanvasText;
}
}(function(){
var root = document.querySelector('.est-01'); if(!root) return;
var chips = root.querySelector('#est-01-chips'), empty = root.querySelector('#est-01-empty'),
list = root.querySelector('#est-01-list'), query = root.querySelector('#est-01-query');
var base = ['is:open','label:regression','owner:platform'];
function paint(){
var live = base.filter(function(t){ var c = chips.querySelector('[data-drop="' + t + '"]'); return c && !c.hasAttribute('data-gone'); });
query.textContent = live.length ? live.join(' ') : 'search all repositories';
var found = live.length < 3;
empty.hidden = found; list.hidden = !found;
}
root.addEventListener('click', function(e){
var drop = e.target.closest('[data-drop]'), act = e.target.closest('[data-act="reset"]');
if(drop){
var chip = chips.querySelector('[data-drop="' + drop.dataset.drop + '"]');
if(chip) chip.setAttribute('data-gone','');
paint(); return;
}
if(act){
chips.querySelectorAll('[data-drop]').forEach(function(c){ c.setAttribute('data-gone',''); });
paint();
}
});
})();(function(){
var root = document.querySelector('.est-01'); if(!root) return;
var chips = root.querySelector('#est-01-chips'), empty = root.querySelector('#est-01-empty'),
list = root.querySelector('#est-01-list'), query = root.querySelector('#est-01-query');
var base = ['is:open','label:regression','owner:platform'];
function paint(){
var live = base.filter(function(t){ var c = chips.querySelector('[data-drop="' + t + '"]'); return c && !c.hasAttribute('data-gone'); });
query.textContent = live.length ? live.join(' ') : 'search all repositories';
var found = live.length < 3;
empty.hidden = found; list.hidden = !found;
}
root.addEventListener('click', function(e){
var drop = e.target.closest('[data-drop]'), act = e.target.closest('[data-act="reset"]');
if(drop){
var chip = chips.querySelector('[data-drop="' + drop.dataset.drop + '"]');
if(chip) chip.setAttribute('data-gone','');
paint(); return;
}
if(act){
chips.querySelectorAll('[data-drop]').forEach(function(c){ c.setAttribute('data-gone',''); });
paint();
}
});
})();Here's a working CSS Empty State from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: No Search Results State
Source: https://codefronts.com/snippets/css-empty-states/no-search-results-state/
A search that returns nothing inside a real issue tracker: filter chips above the results, the query echoed back in monospace, and one primary recovery that removes the filter most likely to be the problem. Dropping a chip swaps the empty state for real rows, so the demo shows both halves of the state machine rather than a poster of the sad half.
## HTML
```html
<div class="est-01">
<div class="est-01__shell">
<nav class="est-01__rail" aria-label="Workspace">
<span class="est-01__mark" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M5 17.5 12 4l7 13.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M8.4 17.5h7.2" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
</span>
<button class="est-01__ri est-01__ri--on" type="button" aria-label="Issues" aria-current="page">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><circle cx="12" cy="12" r="7.5" stroke="currentColor" stroke-width="1.7"/><path d="M12 8.4v4.2M12 15.5h.01" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
</button>
<button class="est-01__ri" type="button" aria-label="Pull requests">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><circle cx="7" cy="6.5" r="2.3" stroke="currentColor" stroke-width="1.7"/><circle cx="7" cy="17.5" r="2.3" stroke="currentColor" stroke-width="1.7"/><circle cx="17" cy="17.5" r="2.3" stroke="currentColor" stroke-width="1.7"/><path d="M7 8.8v6.4M9.3 6.5h5.2a2.5 2.5 0 0 1 2.5 2.5v6.2" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
</button>
<button class="est-01__ri" type="button" aria-label="Deployments">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M4 15.5 12 4l8 11.5" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/><path d="M4.5 19.5h15" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
</button>
<button class="est-01__ri" type="button" aria-label="Insights">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M4 19V6M20 19H4M8 15.5V11M12.5 15.5V8M17 15.5v-3" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
</button>
<span class="est-01__grow"></span>
<span class="est-01__me" aria-hidden="true">AR</span>
</nav>
<div class="est-01__main">
<header class="est-01__top">
<div class="est-01__field">
<svg class="est-01__mag" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="11" cy="11" r="6.2" stroke="currentColor" stroke-width="1.8"/><path d="m15.8 15.8 3.7 3.7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
<span class="est-01__q" id="est-01-query">is:open label:regression owner:platform</span>
<button class="est-01__x" type="button" data-act="reset" aria-label="Clear search">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
</button>
</div>
<div class="est-01__tabs" role="tablist" aria-label="Search scope">
<button class="est-01__tab est-01__tab--on" type="button" role="tab" aria-selected="true">Issues</button>
<button class="est-01__tab" type="button" role="tab" aria-selected="false">Pull requests</button>
<button class="est-01__tab" type="button" role="tab" aria-selected="false">Discussions</button>
</div>
</header>
<div class="est-01__chips" id="est-01-chips">
<button class="est-01__chip" type="button" data-drop="label:regression">label:regression<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
<button class="est-01__chip" type="button" data-drop="owner:platform">owner:platform<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
<button class="est-01__chip" type="button" data-drop="is:open">is:open<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
</div>
<section class="est-01__body" aria-live="polite" aria-atomic="true">
<div class="est-01__empty" id="est-01-empty">
<span class="est-01__glyph" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><circle cx="10.5" cy="10.5" r="6.4" stroke="currentColor" stroke-width="1.6"/><path d="m15.4 15.4 4.1 4.1" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/><path d="M8 10.5h5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
</span>
<h1 class="est-01__h">No issues match all three filters</h1>
<p class="est-01__p">Platform has nothing open with that label.</p>
<div class="est-01__acts">
<button class="est-01__act est-01__act--pri" type="button" data-drop="label:regression">Drop label:regression</button>
<button class="est-01__act" type="button" data-act="reset">Search every repository</button>
</div>
</div>
<ol class="est-01__list" id="est-01-list" hidden>
<li class="est-01__row">
<span class="est-01__dot est-01__dot--open" aria-hidden="true"></span>
<span class="est-01__rmain"><span class="est-01__rt">Retry storm when the queue drains mid-deploy</span><span class="est-01__rm">platform/edge-router · #4821 · opened by dcheng</span></span>
<span class="est-01__pill">needs triage</span>
</li>
<li class="est-01__row">
<span class="est-01__dot est-01__dot--open" aria-hidden="true"></span>
<span class="est-01__rmain"><span class="est-01__rt">Token refresh drops the websocket session</span><span class="est-01__rm">platform/auth · #4804 · opened by mira.k</span></span>
<span class="est-01__pill est-01__pill--alt">in review</span>
</li>
<li class="est-01__row">
<span class="est-01__dot" aria-hidden="true"></span>
<span class="est-01__rmain"><span class="est-01__rt">Cold start regression on the image pipeline</span><span class="est-01__rm">platform/media · #4790 · opened by t.oyelaran</span></span>
<span class="est-01__pill est-01__pill--done">closed</span>
</li>
</ol>
</section>
</div>
</div>
</div>
```
## CSS
```css
@import url('https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap');
.est-01 {
--bg: #0b0c0f;
--panel: #12141a;
--panel-2: #171a21;
--line: #22262f;
--line-2: #2c313c;
--text: #eef0f5;
--muted: #9aa1b1;
--faint: #6b7383;
--accent: #7aa2ff;
--open: #4ade80;
--warn: #f5b661;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
box-sizing: border-box;
background: var(--bg);
color: var(--text);
color-scheme: dark;
font-synthesis: none;
font-family: 'Geist',ui-sans-serif,system-ui,-apple-system,sans-serif;
-webkit-font-smoothing: antialiased;
}
.est-01 *,
.est-01 *::before,
.est-01 *::after {
box-sizing: border-box;
}
.est-01 [hidden] {
display: none !important;
}
@supports (color: oklch(0.7 0.1 300)) {
.est-01 {
--bg: oklch(0.16 0.011 265);
--panel: oklch(0.203 0.013 265);
--panel-2: oklch(0.235 0.015 265);
--line: oklch(0.29 0.014 265);
--line-2: oklch(0.345 0.016 265);
--text: oklch(0.965 0.004 265);
--muted: oklch(0.735 0.021 265);
--faint: oklch(0.585 0.021 265);
--accent: oklch(0.775 0.115 262);
--open: oklch(0.82 0.17 152);
--warn: oklch(0.82 0.11 72);
}
}
.est-01__shell {
min-height: 100vh;
min-height: 100svh;
display: grid;
grid-template-columns: 4.25rem minmax(0,1fr);
}
.est-01__rail {
display: flex;
flex-direction: column;
align-items: center;
gap: .35rem;
padding: 1rem .75rem 1.25rem;
border-inline-end: 1px solid var(--line);
background: linear-gradient(180deg,var(--panel),var(--bg));
}
.est-01__mark {
inline-size: 2.25rem;
block-size: 2.25rem;
display: grid;
place-items: center;
margin-block-end: .75rem;
border-radius: 11px;
color: var(--bg);
background: var(--text);
}
.est-01__mark svg {
inline-size: 1.2rem;
block-size: 1.2rem;
}
.est-01__ri {
inline-size: 2.5rem;
block-size: 2.5rem;
display: grid;
place-items: center;
cursor: pointer;
background: transparent;
border: 1px solid transparent;
border-radius: 11px;
color: var(--faint);
transition: color .18s, background .18s, border-color .18s;
}
.est-01__ri svg {
inline-size: 1.2rem;
block-size: 1.2rem;
}
.est-01__ri:hover {
color: var(--text);
background: var(--panel-2);
}
.est-01__ri--on {
color: var(--text);
background: var(--panel-2);
border-color: var(--line-2);
}
.est-01__ri:focus-visible,
.est-01__x:focus-visible,
.est-01__chip:focus-visible,
.est-01__act:focus-visible,
.est-01__tab:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.est-01__grow {
flex: 1 1 auto;
}
.est-01__me {
inline-size: 2rem;
block-size: 2rem;
display: grid;
place-items: center;
border-radius: 50%;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .68rem;
letter-spacing: .04em;
color: var(--text);
background: var(--panel-2);
border: 1px solid var(--line-2);
}
.est-01__main {
min-inline-size: 0;
display: grid;
grid-template-rows: auto auto minmax(0,1fr);
align-content: start;
}
.est-01__top {
display: flex;
flex-wrap: wrap;
gap: .9rem 1.5rem;
align-items: center;
justify-content: space-between;
padding: 1rem clamp(1rem,3vw,2rem);
border-block-end: 1px solid var(--line);
background: color-mix(in oklab, var(--panel) 70%, transparent);
backdrop-filter: blur(8px);
}
.est-01__field {
flex: 1 1 22rem;
min-inline-size: 0;
display: flex;
align-items: center;
gap: .6rem;
padding: .6rem .7rem .6rem .8rem;
background: var(--panel-2);
border: 1px solid var(--line-2);
border-radius: 12px;
box-shadow: inset 0 1px 0 color-mix(in oklab, #fff 5%, transparent);
}
.est-01__mag {
inline-size: 1.05rem;
block-size: 1.05rem;
flex: none;
color: var(--faint);
}
.est-01__q {
flex: 1 1 auto;
min-inline-size: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .82rem;
letter-spacing: -.01em;
color: var(--text);
}
.est-01__x {
inline-size: 1.6rem;
block-size: 1.6rem;
flex: none;
display: grid;
place-items: center;
cursor: pointer;
color: var(--faint);
background: transparent;
border: 0;
border-radius: 7px;
transition: color .16s, background .16s;
}
.est-01__x svg {
inline-size: .85rem;
block-size: .85rem;
}
.est-01__x:hover {
color: var(--text);
background: var(--line-2);
}
.est-01__tabs {
display: flex;
gap: .15rem;
padding: .2rem;
background: var(--panel-2);
border: 1px solid var(--line);
border-radius: 11px;
}
.est-01__tab {
padding: .42rem .7rem;
font: inherit;
font-size: .8rem;
font-weight: 500;
cursor: pointer;
white-space: nowrap;
color: var(--muted);
background: transparent;
border: 0;
border-radius: 8px;
transition: color .16s, background .16s;
}
.est-01__tab:hover {
color: var(--text);
}
.est-01__tab--on {
color: var(--text);
background: var(--line-2);
box-shadow: 0 1px 2px rgba(0,0,0,.35);
}
.est-01__chips {
display: flex;
flex-wrap: wrap;
gap: .4rem;
padding: .75rem clamp(1rem,3vw,2rem);
border-block-end: 1px solid var(--line);
}
.est-01__chip {
display: inline-flex;
align-items: center;
gap: .4rem;
padding: .34rem .5rem .34rem .6rem;
cursor: pointer;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .72rem;
letter-spacing: -.01em;
color: var(--muted);
background: var(--panel);
border: 1px solid var(--line-2);
border-radius: 8px;
transition: color .16s, border-color .16s, background .16s, opacity .2s, scale .2s;
}
.est-01__chip svg {
inline-size: .6rem;
block-size: .6rem;
opacity: .65;
}
.est-01__chip:hover {
color: var(--text);
background: var(--panel-2);
border-color: var(--accent);
}
.est-01__chip[data-gone] {
opacity: 0;
scale: .9;
pointer-events: none;
}
.est-01__body {
min-block-size: 0;
padding: clamp(1rem,3vw,2rem);
display: grid;
align-content: start;
}
.est-01__empty {
justify-self: center;
align-self: start;
margin-block: clamp(1.5rem,7vh,5rem);
inline-size: min(30rem,100%);
display: grid;
justify-items: center;
text-align: center;
gap: .55rem;
animation: est-01-in .5s cubic-bezier(.2,.7,.3,1) both;
}
@keyframes est-01-in {
from {
opacity: 0;
translate: 0 8px;
}
to {
opacity: 1;
translate: 0 0;
}
}
.est-01__glyph {
position: relative;
inline-size: 5.5rem;
block-size: 5.5rem;
display: grid;
place-items: center;
margin-block-end: .6rem;
border: 1px solid var(--line-2);
border-radius: 18px;
color: var(--muted);
overflow: hidden;
background: radial-gradient(circle at 50% 45%, color-mix(in oklab, var(--accent) 12%, transparent), transparent 62%), var(--panel-2);
}
.est-01__glyph::before {
content: '';
position: absolute;
inset: 0;
background-image: linear-gradient(var(--line) 1px,transparent 1px),linear-gradient(90deg,var(--line) 1px,transparent 1px);
background-size: 11px 11px;
opacity: .55;
mask-image: radial-gradient(circle at 50% 50%, #000 45%, transparent 78%);
}
.est-01__glyph::after {
content: '';
position: absolute;
inset-block: 0;
inline-size: 38%;
background: linear-gradient(90deg,transparent,color-mix(in oklab, var(--accent) 18%, transparent),transparent);
animation: est-01-sweep 5.5s ease-in-out infinite;
}
@keyframes est-01-sweep {
0%,
100% {
translate: -140% 0;
}
50% {
translate: 280% 0;
}
}
.est-01__glyph svg {
position: relative;
inline-size: 1.85rem;
block-size: 1.85rem;
}
.est-01__h {
margin: 0;
font-size: clamp(1.1rem,2.4vw,1.35rem);
font-weight: 600;
letter-spacing: -.025em;
line-height: 1.25;
text-wrap: balance;
}
.est-01__p {
margin: 0;
font-size: .9rem;
line-height: 1.55;
color: var(--muted);
text-wrap: pretty;
}
.est-01__acts {
display: flex;
flex-wrap: wrap;
gap: .5rem;
justify-content: center;
margin-block-start: .85rem;
}
.est-01__act {
min-block-size: 2.75rem;
padding: .6rem 1rem;
font: inherit;
font-size: .85rem;
font-weight: 500;
cursor: pointer;
color: var(--text);
background: var(--panel-2);
border: 1px solid var(--line-2);
border-radius: 11px;
transition: translate .16s, background .16s, border-color .16s;
}
.est-01__act:hover {
translate: 0 -1px;
background: var(--line-2);
}
.est-01__act--pri {
color: #0a0e1a;
background: var(--accent);
border-color: transparent;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .8rem;
letter-spacing: -.01em;
}
.est-01__act--pri:hover {
background: color-mix(in oklab, var(--accent) 88%, #fff);
}
.est-01__list {
margin: 0;
padding: 0;
list-style: none;
display: grid;
gap: .5rem;
inline-size: min(52rem,100%);
justify-self: center;
}
.est-01__row {
display: grid;
grid-template-columns: auto minmax(0,1fr) auto;
gap: .25rem .75rem;
align-items: center;
padding: .85rem 1rem;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 13px;
animation: est-01-in .45s cubic-bezier(.2,.7,.3,1) both;
}
.est-01__row:nth-child(2) {
animation-delay: .06s;
}
.est-01__row:nth-child(3) {
animation-delay: .12s;
}
.est-01__row:hover {
border-color: var(--line-2);
background: var(--panel-2);
}
.est-01__dot {
inline-size: .5rem;
block-size: .5rem;
border-radius: 50%;
background: var(--faint);
}
.est-01__dot--open {
background: var(--open);
box-shadow: 0 0 0 3px color-mix(in oklab, var(--open) 18%, transparent);
}
.est-01__rmain {
min-inline-size: 0;
display: grid;
gap: .2rem;
}
.est-01__rt {
font-size: .9rem;
font-weight: 500;
letter-spacing: -.012em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.est-01__rm {
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .7rem;
color: var(--faint);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.est-01__pill {
padding: .24rem .5rem;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .66rem;
letter-spacing: .02em;
white-space: nowrap;
color: var(--warn);
background: color-mix(in oklab, var(--warn) 12%, transparent);
border: 1px solid color-mix(in oklab, var(--warn) 30%, transparent);
border-radius: 6px;
}
.est-01__pill--alt {
color: var(--accent);
background: color-mix(in oklab, var(--accent) 12%, transparent);
border-color: color-mix(in oklab, var(--accent) 30%, transparent);
}
.est-01__pill--done {
color: var(--faint);
background: var(--panel-2);
border-color: var(--line-2);
}
@media (max-width: 640px) {
.est-01__shell {
grid-template-columns: 1fr;
}
.est-01__rail {
flex-direction: row;
border-inline-end: 0;
border-block-end: 1px solid var(--line);
}
.est-01__mark {
margin: 0 .5rem 0 0;
}
.est-01__pill {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.est-01 *,
.est-01 *::before,
.est-01 *::after {
animation: none !important;
transition: none !important;
}
}
@media (forced-colors: active) {
.est-01__glyph,
.est-01__row,
.est-01__field,
.est-01__act {
border-color: CanvasText;
}
}
```
## JavaScript
```js
(function(){
var root = document.querySelector('.est-01'); if(!root) return;
var chips = root.querySelector('#est-01-chips'), empty = root.querySelector('#est-01-empty'),
list = root.querySelector('#est-01-list'), query = root.querySelector('#est-01-query');
var base = ['is:open','label:regression','owner:platform'];
function paint(){
var live = base.filter(function(t){ var c = chips.querySelector('[data-drop="' + t + '"]'); return c && !c.hasAttribute('data-gone'); });
query.textContent = live.length ? live.join(' ') : 'search all repositories';
var found = live.length < 3;
empty.hidden = found; list.hidden = !found;
}
root.addEventListener('click', function(e){
var drop = e.target.closest('[data-drop]'), act = e.target.closest('[data-act="reset"]');
if(drop){
var chip = chips.querySelector('[data-drop="' + drop.dataset.drop + '"]');
if(chip) chip.setAttribute('data-gone','');
paint(); return;
}
if(act){
chips.querySelectorAll('[data-drop]').forEach(function(c){ c.setAttribute('data-gone',''); });
paint();
}
});
})();
```Here's a working CSS Empty State from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: No Search Results State
Source: https://codefronts.com/snippets/css-empty-states/no-search-results-state/
A search that returns nothing inside a real issue tracker: filter chips above the results, the query echoed back in monospace, and one primary recovery that removes the filter most likely to be the problem. Dropping a chip swaps the empty state for real rows, so the demo shows both halves of the state machine rather than a poster of the sad half.
## HTML
```html
<div class="est-01">
<div class="est-01__shell">
<nav class="est-01__rail" aria-label="Workspace">
<span class="est-01__mark" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M5 17.5 12 4l7 13.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M8.4 17.5h7.2" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
</span>
<button class="est-01__ri est-01__ri--on" type="button" aria-label="Issues" aria-current="page">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><circle cx="12" cy="12" r="7.5" stroke="currentColor" stroke-width="1.7"/><path d="M12 8.4v4.2M12 15.5h.01" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
</button>
<button class="est-01__ri" type="button" aria-label="Pull requests">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><circle cx="7" cy="6.5" r="2.3" stroke="currentColor" stroke-width="1.7"/><circle cx="7" cy="17.5" r="2.3" stroke="currentColor" stroke-width="1.7"/><circle cx="17" cy="17.5" r="2.3" stroke="currentColor" stroke-width="1.7"/><path d="M7 8.8v6.4M9.3 6.5h5.2a2.5 2.5 0 0 1 2.5 2.5v6.2" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
</button>
<button class="est-01__ri" type="button" aria-label="Deployments">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M4 15.5 12 4l8 11.5" stroke="currentColor" stroke-width="1.7" stroke-linejoin="round"/><path d="M4.5 19.5h15" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
</button>
<button class="est-01__ri" type="button" aria-label="Insights">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M4 19V6M20 19H4M8 15.5V11M12.5 15.5V8M17 15.5v-3" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
</button>
<span class="est-01__grow"></span>
<span class="est-01__me" aria-hidden="true">AR</span>
</nav>
<div class="est-01__main">
<header class="est-01__top">
<div class="est-01__field">
<svg class="est-01__mag" viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><circle cx="11" cy="11" r="6.2" stroke="currentColor" stroke-width="1.8"/><path d="m15.8 15.8 3.7 3.7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
<span class="est-01__q" id="est-01-query">is:open label:regression owner:platform</span>
<button class="est-01__x" type="button" data-act="reset" aria-label="Clear search">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="1.9" stroke-linecap="round"/></svg>
</button>
</div>
<div class="est-01__tabs" role="tablist" aria-label="Search scope">
<button class="est-01__tab est-01__tab--on" type="button" role="tab" aria-selected="true">Issues</button>
<button class="est-01__tab" type="button" role="tab" aria-selected="false">Pull requests</button>
<button class="est-01__tab" type="button" role="tab" aria-selected="false">Discussions</button>
</div>
</header>
<div class="est-01__chips" id="est-01-chips">
<button class="est-01__chip" type="button" data-drop="label:regression">label:regression<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
<button class="est-01__chip" type="button" data-drop="owner:platform">owner:platform<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
<button class="est-01__chip" type="button" data-drop="is:open">is:open<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" focusable="false"><path d="M7 7l10 10M17 7 7 17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
</div>
<section class="est-01__body" aria-live="polite" aria-atomic="true">
<div class="est-01__empty" id="est-01-empty">
<span class="est-01__glyph" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" focusable="false"><circle cx="10.5" cy="10.5" r="6.4" stroke="currentColor" stroke-width="1.6"/><path d="m15.4 15.4 4.1 4.1" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/><path d="M8 10.5h5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg>
</span>
<h1 class="est-01__h">No issues match all three filters</h1>
<p class="est-01__p">Platform has nothing open with that label.</p>
<div class="est-01__acts">
<button class="est-01__act est-01__act--pri" type="button" data-drop="label:regression">Drop label:regression</button>
<button class="est-01__act" type="button" data-act="reset">Search every repository</button>
</div>
</div>
<ol class="est-01__list" id="est-01-list" hidden>
<li class="est-01__row">
<span class="est-01__dot est-01__dot--open" aria-hidden="true"></span>
<span class="est-01__rmain"><span class="est-01__rt">Retry storm when the queue drains mid-deploy</span><span class="est-01__rm">platform/edge-router · #4821 · opened by dcheng</span></span>
<span class="est-01__pill">needs triage</span>
</li>
<li class="est-01__row">
<span class="est-01__dot est-01__dot--open" aria-hidden="true"></span>
<span class="est-01__rmain"><span class="est-01__rt">Token refresh drops the websocket session</span><span class="est-01__rm">platform/auth · #4804 · opened by mira.k</span></span>
<span class="est-01__pill est-01__pill--alt">in review</span>
</li>
<li class="est-01__row">
<span class="est-01__dot" aria-hidden="true"></span>
<span class="est-01__rmain"><span class="est-01__rt">Cold start regression on the image pipeline</span><span class="est-01__rm">platform/media · #4790 · opened by t.oyelaran</span></span>
<span class="est-01__pill est-01__pill--done">closed</span>
</li>
</ol>
</section>
</div>
</div>
</div>
```
## CSS
```css
@import url('https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500&display=swap');
.est-01 {
--bg: #0b0c0f;
--panel: #12141a;
--panel-2: #171a21;
--line: #22262f;
--line-2: #2c313c;
--text: #eef0f5;
--muted: #9aa1b1;
--faint: #6b7383;
--accent: #7aa2ff;
--open: #4ade80;
--warn: #f5b661;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
box-sizing: border-box;
background: var(--bg);
color: var(--text);
color-scheme: dark;
font-synthesis: none;
font-family: 'Geist',ui-sans-serif,system-ui,-apple-system,sans-serif;
-webkit-font-smoothing: antialiased;
}
.est-01 *,
.est-01 *::before,
.est-01 *::after {
box-sizing: border-box;
}
.est-01 [hidden] {
display: none !important;
}
@supports (color: oklch(0.7 0.1 300)) {
.est-01 {
--bg: oklch(0.16 0.011 265);
--panel: oklch(0.203 0.013 265);
--panel-2: oklch(0.235 0.015 265);
--line: oklch(0.29 0.014 265);
--line-2: oklch(0.345 0.016 265);
--text: oklch(0.965 0.004 265);
--muted: oklch(0.735 0.021 265);
--faint: oklch(0.585 0.021 265);
--accent: oklch(0.775 0.115 262);
--open: oklch(0.82 0.17 152);
--warn: oklch(0.82 0.11 72);
}
}
.est-01__shell {
min-height: 100vh;
min-height: 100svh;
display: grid;
grid-template-columns: 4.25rem minmax(0,1fr);
}
.est-01__rail {
display: flex;
flex-direction: column;
align-items: center;
gap: .35rem;
padding: 1rem .75rem 1.25rem;
border-inline-end: 1px solid var(--line);
background: linear-gradient(180deg,var(--panel),var(--bg));
}
.est-01__mark {
inline-size: 2.25rem;
block-size: 2.25rem;
display: grid;
place-items: center;
margin-block-end: .75rem;
border-radius: 11px;
color: var(--bg);
background: var(--text);
}
.est-01__mark svg {
inline-size: 1.2rem;
block-size: 1.2rem;
}
.est-01__ri {
inline-size: 2.5rem;
block-size: 2.5rem;
display: grid;
place-items: center;
cursor: pointer;
background: transparent;
border: 1px solid transparent;
border-radius: 11px;
color: var(--faint);
transition: color .18s, background .18s, border-color .18s;
}
.est-01__ri svg {
inline-size: 1.2rem;
block-size: 1.2rem;
}
.est-01__ri:hover {
color: var(--text);
background: var(--panel-2);
}
.est-01__ri--on {
color: var(--text);
background: var(--panel-2);
border-color: var(--line-2);
}
.est-01__ri:focus-visible,
.est-01__x:focus-visible,
.est-01__chip:focus-visible,
.est-01__act:focus-visible,
.est-01__tab:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.est-01__grow {
flex: 1 1 auto;
}
.est-01__me {
inline-size: 2rem;
block-size: 2rem;
display: grid;
place-items: center;
border-radius: 50%;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .68rem;
letter-spacing: .04em;
color: var(--text);
background: var(--panel-2);
border: 1px solid var(--line-2);
}
.est-01__main {
min-inline-size: 0;
display: grid;
grid-template-rows: auto auto minmax(0,1fr);
align-content: start;
}
.est-01__top {
display: flex;
flex-wrap: wrap;
gap: .9rem 1.5rem;
align-items: center;
justify-content: space-between;
padding: 1rem clamp(1rem,3vw,2rem);
border-block-end: 1px solid var(--line);
background: color-mix(in oklab, var(--panel) 70%, transparent);
backdrop-filter: blur(8px);
}
.est-01__field {
flex: 1 1 22rem;
min-inline-size: 0;
display: flex;
align-items: center;
gap: .6rem;
padding: .6rem .7rem .6rem .8rem;
background: var(--panel-2);
border: 1px solid var(--line-2);
border-radius: 12px;
box-shadow: inset 0 1px 0 color-mix(in oklab, #fff 5%, transparent);
}
.est-01__mag {
inline-size: 1.05rem;
block-size: 1.05rem;
flex: none;
color: var(--faint);
}
.est-01__q {
flex: 1 1 auto;
min-inline-size: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .82rem;
letter-spacing: -.01em;
color: var(--text);
}
.est-01__x {
inline-size: 1.6rem;
block-size: 1.6rem;
flex: none;
display: grid;
place-items: center;
cursor: pointer;
color: var(--faint);
background: transparent;
border: 0;
border-radius: 7px;
transition: color .16s, background .16s;
}
.est-01__x svg {
inline-size: .85rem;
block-size: .85rem;
}
.est-01__x:hover {
color: var(--text);
background: var(--line-2);
}
.est-01__tabs {
display: flex;
gap: .15rem;
padding: .2rem;
background: var(--panel-2);
border: 1px solid var(--line);
border-radius: 11px;
}
.est-01__tab {
padding: .42rem .7rem;
font: inherit;
font-size: .8rem;
font-weight: 500;
cursor: pointer;
white-space: nowrap;
color: var(--muted);
background: transparent;
border: 0;
border-radius: 8px;
transition: color .16s, background .16s;
}
.est-01__tab:hover {
color: var(--text);
}
.est-01__tab--on {
color: var(--text);
background: var(--line-2);
box-shadow: 0 1px 2px rgba(0,0,0,.35);
}
.est-01__chips {
display: flex;
flex-wrap: wrap;
gap: .4rem;
padding: .75rem clamp(1rem,3vw,2rem);
border-block-end: 1px solid var(--line);
}
.est-01__chip {
display: inline-flex;
align-items: center;
gap: .4rem;
padding: .34rem .5rem .34rem .6rem;
cursor: pointer;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .72rem;
letter-spacing: -.01em;
color: var(--muted);
background: var(--panel);
border: 1px solid var(--line-2);
border-radius: 8px;
transition: color .16s, border-color .16s, background .16s, opacity .2s, scale .2s;
}
.est-01__chip svg {
inline-size: .6rem;
block-size: .6rem;
opacity: .65;
}
.est-01__chip:hover {
color: var(--text);
background: var(--panel-2);
border-color: var(--accent);
}
.est-01__chip[data-gone] {
opacity: 0;
scale: .9;
pointer-events: none;
}
.est-01__body {
min-block-size: 0;
padding: clamp(1rem,3vw,2rem);
display: grid;
align-content: start;
}
.est-01__empty {
justify-self: center;
align-self: start;
margin-block: clamp(1.5rem,7vh,5rem);
inline-size: min(30rem,100%);
display: grid;
justify-items: center;
text-align: center;
gap: .55rem;
animation: est-01-in .5s cubic-bezier(.2,.7,.3,1) both;
}
@keyframes est-01-in {
from {
opacity: 0;
translate: 0 8px;
}
to {
opacity: 1;
translate: 0 0;
}
}
.est-01__glyph {
position: relative;
inline-size: 5.5rem;
block-size: 5.5rem;
display: grid;
place-items: center;
margin-block-end: .6rem;
border: 1px solid var(--line-2);
border-radius: 18px;
color: var(--muted);
overflow: hidden;
background: radial-gradient(circle at 50% 45%, color-mix(in oklab, var(--accent) 12%, transparent), transparent 62%), var(--panel-2);
}
.est-01__glyph::before {
content: '';
position: absolute;
inset: 0;
background-image: linear-gradient(var(--line) 1px,transparent 1px),linear-gradient(90deg,var(--line) 1px,transparent 1px);
background-size: 11px 11px;
opacity: .55;
mask-image: radial-gradient(circle at 50% 50%, #000 45%, transparent 78%);
}
.est-01__glyph::after {
content: '';
position: absolute;
inset-block: 0;
inline-size: 38%;
background: linear-gradient(90deg,transparent,color-mix(in oklab, var(--accent) 18%, transparent),transparent);
animation: est-01-sweep 5.5s ease-in-out infinite;
}
@keyframes est-01-sweep {
0%,
100% {
translate: -140% 0;
}
50% {
translate: 280% 0;
}
}
.est-01__glyph svg {
position: relative;
inline-size: 1.85rem;
block-size: 1.85rem;
}
.est-01__h {
margin: 0;
font-size: clamp(1.1rem,2.4vw,1.35rem);
font-weight: 600;
letter-spacing: -.025em;
line-height: 1.25;
text-wrap: balance;
}
.est-01__p {
margin: 0;
font-size: .9rem;
line-height: 1.55;
color: var(--muted);
text-wrap: pretty;
}
.est-01__acts {
display: flex;
flex-wrap: wrap;
gap: .5rem;
justify-content: center;
margin-block-start: .85rem;
}
.est-01__act {
min-block-size: 2.75rem;
padding: .6rem 1rem;
font: inherit;
font-size: .85rem;
font-weight: 500;
cursor: pointer;
color: var(--text);
background: var(--panel-2);
border: 1px solid var(--line-2);
border-radius: 11px;
transition: translate .16s, background .16s, border-color .16s;
}
.est-01__act:hover {
translate: 0 -1px;
background: var(--line-2);
}
.est-01__act--pri {
color: #0a0e1a;
background: var(--accent);
border-color: transparent;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .8rem;
letter-spacing: -.01em;
}
.est-01__act--pri:hover {
background: color-mix(in oklab, var(--accent) 88%, #fff);
}
.est-01__list {
margin: 0;
padding: 0;
list-style: none;
display: grid;
gap: .5rem;
inline-size: min(52rem,100%);
justify-self: center;
}
.est-01__row {
display: grid;
grid-template-columns: auto minmax(0,1fr) auto;
gap: .25rem .75rem;
align-items: center;
padding: .85rem 1rem;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 13px;
animation: est-01-in .45s cubic-bezier(.2,.7,.3,1) both;
}
.est-01__row:nth-child(2) {
animation-delay: .06s;
}
.est-01__row:nth-child(3) {
animation-delay: .12s;
}
.est-01__row:hover {
border-color: var(--line-2);
background: var(--panel-2);
}
.est-01__dot {
inline-size: .5rem;
block-size: .5rem;
border-radius: 50%;
background: var(--faint);
}
.est-01__dot--open {
background: var(--open);
box-shadow: 0 0 0 3px color-mix(in oklab, var(--open) 18%, transparent);
}
.est-01__rmain {
min-inline-size: 0;
display: grid;
gap: .2rem;
}
.est-01__rt {
font-size: .9rem;
font-weight: 500;
letter-spacing: -.012em;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.est-01__rm {
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .7rem;
color: var(--faint);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.est-01__pill {
padding: .24rem .5rem;
font-family: 'Geist Mono',ui-monospace,monospace;
font-size: .66rem;
letter-spacing: .02em;
white-space: nowrap;
color: var(--warn);
background: color-mix(in oklab, var(--warn) 12%, transparent);
border: 1px solid color-mix(in oklab, var(--warn) 30%, transparent);
border-radius: 6px;
}
.est-01__pill--alt {
color: var(--accent);
background: color-mix(in oklab, var(--accent) 12%, transparent);
border-color: color-mix(in oklab, var(--accent) 30%, transparent);
}
.est-01__pill--done {
color: var(--faint);
background: var(--panel-2);
border-color: var(--line-2);
}
@media (max-width: 640px) {
.est-01__shell {
grid-template-columns: 1fr;
}
.est-01__rail {
flex-direction: row;
border-inline-end: 0;
border-block-end: 1px solid var(--line);
}
.est-01__mark {
margin: 0 .5rem 0 0;
}
.est-01__pill {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.est-01 *,
.est-01 *::before,
.est-01 *::after {
animation: none !important;
transition: none !important;
}
}
@media (forced-colors: active) {
.est-01__glyph,
.est-01__row,
.est-01__field,
.est-01__act {
border-color: CanvasText;
}
}
```
## JavaScript
```js
(function(){
var root = document.querySelector('.est-01'); if(!root) return;
var chips = root.querySelector('#est-01-chips'), empty = root.querySelector('#est-01-empty'),
list = root.querySelector('#est-01-list'), query = root.querySelector('#est-01-query');
var base = ['is:open','label:regression','owner:platform'];
function paint(){
var live = base.filter(function(t){ var c = chips.querySelector('[data-drop="' + t + '"]'); return c && !c.hasAttribute('data-gone'); });
query.textContent = live.length ? live.join(' ') : 'search all repositories';
var found = live.length < 3;
empty.hidden = found; list.hidden = !found;
}
root.addEventListener('click', function(e){
var drop = e.target.closest('[data-drop]'), act = e.target.closest('[data-act="reset"]');
if(drop){
var chip = chips.querySelector('[data-drop="' + drop.dataset.drop + '"]');
if(chip) chip.setAttribute('data-gone','');
paint(); return;
}
if(act){
chips.querySelectorAll('[data-drop]').forEach(function(c){ c.setAttribute('data-gone',''); });
paint();
}
});
})();
```How this works
The shell first. An empty state is only convincing inside real chrome, and the chrome has to survive a narrow viewport. Two tracks, and only the second one is allowed to collapse:
.est-01__shell{ display:grid; grid-template-columns:4.25rem minmax(0,1fr); }
.est-01__main{ min-inline-size:0; } /* lets the query ellipsis work */The glyph is three stacked layers. A tinted radial for depth, a hairline grid for the instrument feel, and a mask so the grid fades out instead of ending in a hard rectangle:
.est-01__glyph::before{
background-image:linear-gradient(var(--line) 1px,transparent 1px),
linear-gradient(90deg,var(--line) 1px,transparent 1px);
background-size:11px 11px;
mask-image:radial-gradient(circle at 50% 50%, #000 45%, transparent 78%);
}The sweep moves one pseudo-element. Animating translate keeps it on the compositor; animating background-position on the panel would not:
@keyframes est-01-sweep{ 0%,100%{ translate:-140% 0 } 50%{ translate:280% 0 } }Swapping empty for results. The chip carries the query term it owns, so removing it is a data operation, not a DOM search. When fewer than three filters survive, results exist:
var live = base.filter(t => !chips.querySelector(sel(t)).hasAttribute('data-gone'));
empty.hidden = live.length < 3;
list.hidden = !(live.length < 3);The one line that makes hidden work at all is scoped, not global — display:grid on the empty panel would otherwise win against the browser default.
Make it yours
- Swap the three filter terms for your own facets — the JS reads them from
data-drop, so the markup is the source of truth - Change the recovery heuristic: instead of dropping the last filter, drop the one with the highest cardinality if your backend can tell you
- Replace the sweep with a static tint if the surface sits next to other animated UI
- Move the results list into the same container and cross-fade with
@starting-styleif you target Chrome 117+ only - For search-as-you-type, debounce and keep the empty state mounted so the live region is not recreated on every keystroke
- Light theme: invert the six tokens at the top of the block — nothing else in the demo hard-codes a colour
Gotchas — read before shipping
- Any element you toggle with
hiddenmust not setdisplay, or the attribute silently does nothing. One scoped[hidden]{display:none !important}rule solves it for the whole component - A monospace query needs
min-inline-size:0on every grid ancestor beforetext-overflow:ellipsiswill trigger - Do not put
aria-liveon the element you replace — put it on the stable container, or the announcement is lost with the node backdrop-filtercreates a containing block: absolutely positioned children of the header will anchor to it, not to the page- Never write the query back into the heading as prose. Echo it in a monospace field where a user can see the exact characters, including the trailing space that broke the search
- Dropping a filter must change the visible chip set as well as the result set, or users think the button did nothing
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 114+ | 17.5+ | 121+ | 114+ |
Floor set by oklch(), color-mix(), backdrop-filter, text-wrap as this demo is written. The core technique itself goes back further — Chrome 111+.
Layout and copy work everywhere. color-mix() (Chrome 111 / Safari 16.2 / Firefox 113) and oklch() are wrapped in @supports, with hex fallbacks declared first. mask-image needs -webkit-mask-image below Safari 15.4; without it the grid simply ends squarely. backdrop-filter degrades to a solid panel.