Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,41 @@ <h2 id="forms-title">Forms</h2>
실험 이름
<input name="name" required minlength="3" placeholder="예: 선언형 메뉴" />
</label>
<div class="field-group">
<div class="field-heading">
<label for="review-email">검토자 이메일</label>
<button
type="button"
class="help-trigger"
popovertarget="email-help"
aria-label="이메일 검증 도움말"
>
?
</button>
</div>
<input
id="review-email"
name="email"
type="email"
required
autocomplete="email"
placeholder="ui@example.com"
aria-describedby="email-hint email-invalid email-valid"
/>
<p id="email-hint" class="field-hint">
제출 전 브라우저가 필수 입력과 이메일 형식을 검증합니다.
</p>
<p id="email-invalid" class="validation-message validation-message-invalid">
필수 이메일 형식을 확인하세요.
</p>
<p id="email-valid" class="validation-message validation-message-valid">
이메일 형식이 유효합니다.
</p>
<div id="email-help" class="help-popover" popover>
<strong>Native validation</strong>
<p>required와 type=email만으로 빈 값과 이메일 형식 오류를 브라우저가 처리합니다.</p>
</div>
</div>
<label>
컴포넌트 후보
<input
Expand Down
77 changes: 77 additions & 0 deletions styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,18 @@
left: anchor(left);
margin: 8px 0 0;
}

button[popovertarget='email-help'] {
anchor-name: --email-help-trigger;
}

#email-help:popover-open {
position-anchor: --email-help-trigger;
inset: auto;
top: anchor(bottom);
right: anchor(right);
margin: 8px 0 0;
}
}

.form-card,
Expand All @@ -215,6 +227,71 @@
line-height: 1.6;
}

.field-group {
display: grid;
gap: 8px;
}

.field-heading {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}

.field-heading label {
display: block;
}

.help-trigger {
width: 32px;
min-width: 32px;
min-height: 32px;
padding: 0;
border-radius: 50%;
font-weight: 900;
line-height: 1;
}

.help-popover {
width: min(280px, calc(100vw - 32px));
border: 1px solid var(--color-border);
border-radius: var(--radius-frame);
padding: 14px 16px;
background: var(--color-surface);
box-shadow: var(--shadow-popover);
}

.help-popover p {
margin: 8px 0 0;
color: var(--color-muted);
font-size: 14px;
line-height: 1.6;
}

.validation-message {
display: none;
margin: -2px 0 0;
font-size: 14px;
font-weight: 800;
line-height: 1.55;
}

.validation-message-invalid {
color: var(--color-invalid);
}

.validation-message-valid {
color: var(--color-valid);
}

@supports selector(.field-group:has(input:user-invalid)) {
.field-group:has(input:user-invalid) .validation-message-invalid,
.field-group:has(input:user-valid) .validation-message-valid {
display: block;
}
}

input:not([type='radio']):not([type='checkbox']),
select {
min-height: 44px;
Expand Down
Loading