자동 완성 이벤트

커뮤니티 그룹 보고서 초안,

이 버전:
https://wicg.github.io/autofill-event/
이슈 추적:
GitHub
편집자:
(Shopify)

초록

이 명세는 사용자 에이전트가 양식 필드를 자동 완성하려 할 때 발생하는 이벤트를 정의하여, 개발자가 자동 완성된 값을 기반으로 양식을 동적으로 조정할 수 있도록 한다.

이 문서의 상태

이 명세는 웹 플랫폼 인큐베이터 커뮤니티 그룹에서 발행했다. 이는 W3C 표준이 아니며 W3C 표준화 절차에도 속하지 않는다. 다음 사항에 유의한다. W3C 커뮤니티 기여자 라이선스 계약 (CLA) 에 따라 제한적인 옵트아웃이 허용되며 기타 조건이 적용된다. W3C 커뮤니티 및 비즈니스 그룹에 대해 자세히 알아본다.

1. 소개

이 절은 비규범적이다.

자동 완성은 매일 수백만 사용자의 불편을 줄여 주는 웹의 핵심 기능이다. 몇 가지 예를 들면 로그인 화면, 전자상거래, 연락처 양식에서 널리 사용된다. 특히 상거래 및 결제 흐름에서 자동 완성은 구매자 경험과 판매자 성과 모두에 상당한 이점을 제공한다.

동시에 웹의 자동 완성에는 부분적이거나 불완전한 입력, 브라우저 간 상호 운용성 문제, 개발자의 높은 구현 및 유지관리 비용이라는 여러 결함이 있다.

한 가지 주요 예는 주소 자동 완성으로, 올바르게 구현할 경우 동적 양식이 된다. 지역마다 주소 입력의 형식과 요구사항이 다르다. 국가를 선택하려면 양식을 변경해야 하고(필드 순서 변경, 필드 추가 및 제거), 사용자의 입력에 따라 달라지지만 자동 완성이 이 상호작용을 중개하므로 렌더링된 양식에 올바르게 응답하지 않을 수 있다.

현재의 '업계 표준' 해결책은 올바른 정보를 예상하여 수집한 다음 사용자에게 표시하려는 숨겨진 양식 필드를 사용해야 한다. 이 해결책은 취약하고 복잡하다. 더 나쁜 점은 합법적인 사용 사례를 지원하기 위해 숨겨진 필드를 사용하는 관행을 고착화하지만, 같은 기법이 악의적인 행위자에 의해 악용될 수 있고 실제로 악용되고 있다는 것이다.

이 명세는 자동 완성 값이 양식 필드에 적용되기 전에 발생하는 AutofillEvent를 도입하여 개발자가 다음을 수행할 수 있도록 한다.

  1. 자동 완성되려는 값을 검사한다

  2. 해당 값을 기반으로 양식을 동적으로 조정한다(예: 국가별 주소 필드 표시)

  3. 양식이 자동 완성 값을 받을 준비가 되었을 때 사용자 에이전트에 신호를 보낸다

1.1. 목표

1.2. 예제

자동 완성된 국가 값을 기반으로 국가별 주소 필드를 동적으로 추가하는 결제 양식:
<form id="checkout">
  <input autocomplete="name" placeholder="전체 이름">
  <input autocomplete="street-address" placeholder="도로명 주소">
  <input autocomplete="address-level2" placeholder="도시">
  <input autocomplete="postal-code" placeholder="우편번호">
  <input autocomplete="country" placeholder="국가">
  <!-- 필요한 국가에는 주/도 필드가 동적으로 추가된다 -->
</form>

<script>
document.addEventListener('autofill', async function(event) {
  // 자동 완성 값에서 국가 값을 찾는다
  let countryValue = null;
  let formElement = null;

  // 국가 요소와 값을 찾는다
  for (const [element, value] of event.autofillValues) {
    if (element.autocomplete === 'country') {
      countryValue = value;
      formElement = element.form;
      break;
    }
  }

  // 미국 주소를 입력하는 경우 주 선택기를 추가해야 한다
  if (event.refill !== null) {
    if (countryValue === 'US') {
        // 이미 주 필드가 있는지 확인한다
        const existingState = formElement.querySelector('[autocomplete="address-level1"]');
        if (!existingState) {
        // 미국 주소용 주 선택기를 생성하고 삽입한다
        const stateSelect = document.createElement('select');
        stateSelect.autocomplete = 'address-level1';
        stateSelect.name = 'state';
        stateSelect.innerHTML = `
            <option value="">주 선택...</option>
            <option value="AL">앨라배마</option>
            <option value="AK">알래스카</option>
            <option value="AZ">애리조나</option>
            <option value="CA">캘리포니아</option>
            <option value="CO">콜로라도</option>
            <!-- ... 기타 주 ... -->
            <option value="WY">와이오밍</option>
        `;

        // 우편번호 필드 앞에 삽입한다
        const postalCode = formElement.querySelector('[autocomplete="postal-code"]');
        postalCode.parentNode.insertBefore(stateSelect, postalCode);

        // 양식이 수정되었으며 자동 완성을 다시 수행해야 함을 알린다
        await event.refill();
        }
    } else if (countryValue === 'UK') {
        ... Add UK-specific logic
    }
  } else {
    // UA가 재입력을 지원하지 않는다. 숨겨진 필드에서 값을 추출하거나,
    // 사용자에게 값을 수동으로 완성해야 한다고 알린다.
  }
});
</script>

autofillValues 속성은 자동 완성 값 항목의 목록을 반환하며, 각 항목은 대상 HTMLElement와 입력할 값으로 이루어진 튜플이다. 개발자는 이러한 항목을 순회하여 대기 중인 자동 완성 데이터를 검사하고 양식을 조정해야 하는지 판단할 수 있다.

양식 구조가 변경되면(예: 국가별 필드를 추가하며, 잠재적으로 비동기적으로 수행되는 경우), 개발자는 refill을 호출한다. 이는 양식이 수정되었으며 갱신된 양식 구조를 사용해 자동 완성 작업을 다시 시도해야 한다는 것을 사용자 에이전트에 알린다.

참고: refill 속성은 이벤트가 두 번째로 디스패치될 때 (양식 수정 후) null이 되어 무한 루프를 방지한다.

2. 개념

2.1. 자동 완성 값 항목

자동 완성 값 항목은 다음으로 구성된 튜플이다.

  1. HTMLElement — 자동 완성 값을 받을 양식 컨트롤

  2. DOMString — 입력할 사용자 자동 완성 프로필의 값

사용자 에이전트는 컨트롤의 autocomplete 속성을 기반으로 양식 컨트롤을 자동 완성 데이터와 일치시킨다([HTML]자동 완성 필드 이름 참조). 또한 구현 정의 휴리스틱을 사용할 수도 있다.

2.2. 재입력 작업

재입력 작업을 사용하면 개발자는 자동 완성 값에 응답하여 양식 구조가 수정되었으며 사용자 에이전트가 양식 입력을 다시 시도해야 한다는 신호를 보낼 수 있다.

3. AutofillEvent 인터페이스

[Exposed=Window]
interface AutofillEvent : Event {
  constructor(DOMString type, optional AutofillEventInit eventInitDict = {});
  readonly attribute FrozenArray<AutofillValueEntry> autofillValues;
  readonly attribute RefillCallback? refill;
};

callback RefillCallback = Promise<undefined> ();

dictionary AutofillEventInit : EventInit {
  sequence<AutofillValueEntry> autofillValues = [];
  boolean allowRefill = true;
};

typedef sequence<any> AutofillValueEntry;
// AutofillValueEntry는 [HTMLElement, DOMString]의 튜플이다
// 첫 번째 요소는 양식 컨트롤이고 두 번째 요소는 입력할 값이다

AutofillEvent 인터페이스는 사용자 에이전트가 양식 필드를 자동 완성하려 할 때 디스패치되는 이벤트를 나타낸다.

3.1. 속성

autofillValues 속성은 자동 완성 값 항목의 목록을 반환한다. 각 항목은 첫 번째 요소가 HTMLElement (입력될 양식 컨트롤)이고 두 번째 요소가 DOMString (입력할 값)인 튜플이다.

refill 속성은 RefillCallback 또는 null을 반환한다. null이 아닐 때 이 콜백을 호출하면 Promise가 반환되며, 이를 기다리면 양식 구조가 수정되었고 자동 완성을 다시 시도해야 한다는 신호를 사용자 에이전트에 보낸다.

refill 속성은 다음 경우에 null이다.

이는 페이지가 양식을 계속 수정하고 재입력을 요청하는 무한 루프를 방지한다.

AutofillEvent에는 처음에 빈 목록인, 연관된 자동 완성 값 목록 (자동 완성 값 항목목록)이 있다.

AutofillEvent에는 처음에 true인, 연관된 재입력 허용 플래그 (불리언)가 있다.

AutofillEvent에는 처음에 0인, 연관된 디스패치 타임스탬프 (DOMHighResTimeStamp)가 있다.

AutofillEvent에는 처음에 false인, 연관된 재입력 대기 플래그 (불리언)가 있다.

4. 처리 모델

4.1. 자동 완성 이벤트 발생

문서 document, 자동 완성 값 항목목록 entries, 그리고 불리언 allowRefill이 주어졌을 때 자동 완성 이벤트를 발생시키려면:
  1. eventAutofillEvent를 사용하여 이벤트를 생성한 결과로 둔다.

  2. eventtype 속성을 "autofill"로 초기화한다.

  3. eventbubbles 속성을 true로 초기화한다.

  4. eventcancelable 속성을 false로 초기화한다.

  5. event자동 완성 값 목록entries로 설정한다.

  6. event재입력 허용 플래그allowRefill로 설정한다.

  7. event디스패치 타임스탬프현재 고해상도 시간으로 설정한다.

  8. document에서 event디스패치한다.

  9. document에서 entries를 사용하여 자동 완성 작업을 수행한다.

참고: 자동 완성 작업은 이벤트가 디스패치된 직후 수행된다. refill 콜백을 사용하면 페이지가 양식 구조를 수정한 후 구현 정의 제한 시간 내에서 추가 자동 완성 단계를 요청할 수 있다.

4.2. 재입력 요청 처리

AutofillEvent event가 주어졌을 때 재입력 요청을 처리하려면:
  1. now현재 고해상도 시간으로 둔다.

  2. elapsednow에서 event디스패치 타임스탬프를 뺀 값으로 둔다.

  3. refillTimeout구현 정의 기간으로 둔다.

  4. elapsedrefillTimeout보다 크면 "InvalidStateError" DOMException으로 거부된 프로미스를 반환한다.

  5. event재입력 허용 플래그가 false이면 "InvalidStateError" DOMException으로 거부된 프로미스를 반환한다.

  6. event재입력 대기 플래그가 true이면 "InvalidStateError" DOMException으로 거부된 프로미스를 반환한다.

  7. event재입력 대기 플래그를 true로 설정한다.

  8. promise새 프로미스로 둔다.

  9. documentevent의 관련 문서로 둔다.

  10. promise를 반환하고 병렬로 다음을 수행한다.

    1. entries를 갱신된 자동 완성 값 항목으로 둔다(수정된 양식에 대해 사용자의 자동 완성 데이터를 다시 일치시킨다).

    2. 다음을 수행하도록 태스크를 큐에 추가한다.

      1. document, entries, false를 사용하여 자동 완성 이벤트를 발생시킨다.

      2. document에서 entries를 사용하여 자동 완성 작업을 수행한다.

      3. promise를 undefined로 이행한다.

참고: 제한 시간은 사용자 에이전트가 응답성과 페이지에 refill을 호출할 충분한 시간을 제공하는 것 사이의 균형을 유연하게 조정할 수 있도록 구현 정의된다. 사용자 에이전트는 좋은 사용자 경험을 제공하는 제한 시간을 선택하는 것이 좋다.

참고: 재시도 디스패치 시(refill이 호출된 후) refill 속성은 null이 되어 무한 루프를 방지한다.

4.3. HTML 자동 완성과의 통합

사용자 에이전트의 자동 완성 메커니즘이 트리거되고(예: 사용자가 자동 완성 UI와 상호작용하여), 사용자가 입력할 값을 선택하면 사용자 에이전트는 해당 값을 양식 필드에 적용하기 전에 반드시 자동 완성 이벤트를 발생시켜야 한다.

5. "full-address" 자동 완성 토큰

이 명세는 새로운 자동 완성 필드 이름인 "full-address"를 도입한다.

양식 컨트롤autocomplete 속성이 "full-address"로 설정된 경우, 사용자 에이전트는 현재 양식에 없을 수도 있는 필드를 포함하여 사용자의 전체 주소 데이터에 접근할 권한을 요청하는 것이 좋다.

이를 통해 양식은 AutofillEvent를 통해 포괄적인 주소 정보를 수신하고, 사용자의 주소와 관련된 모든 필드를 수용하도록 구조를 동적으로 조정할 수 있다.

포괄적인 주소 자동 완성을 활성화하기 위해 full-address 사용:
<form autocomplete="full-address">
  <input name="country" autocomplete="country">
  <div id="dynamic-address-fields"></div>
</form>

6. 보안 및 개인정보 보호 고려 사항

AutofillEvent는 자동 완성 값이 양식 필드에 적용되기 전에 이를 JavaScript에 노출한다. 사용자 에이전트는 자동 완성에 대한 명시적인 사용자 동의를 받은 후에만 이벤트가 발생하도록 하는 것이 좋다(예: 드롭다운에서 자동 완성 제안을 선택한 경우).

이벤트에 전달되는 데이터는 API 형태상 자동 완성 값의 키로 요소가 필요하므로, 사용자 에이전트가 페이지의 양식에 입력하려는 데이터로 제한된다.

refill() 호출 후 이벤트가 발생할 때는 양식에 사용자 에이전트가 처음 양식을 입력했을 때 존재하지 않았던 새 필드가 포함될 가능성이 높다는 점에 유의한다. 사용자 에이전트는 새 양식 필드를 입력하기 전에 여전히 사용자의 동의를 고려해야 하며, 이는 자동 재입력을 지원하는 사용자 에이전트에서 이미 적용되는 방식과 같다.

6.1. 서드 파티 자동 완성 제공자

브라우저 확장 프로그램과 서드 파티 자동 완성 제공자(예: 비밀번호 관리자)는 동일한 구조의 AutofillEvent를 생성하고 디스패치하여 이 API를 활용할 수 있으며, 이를 통해 자동 완성 소스와 관계없이 일관된 동작을 보장할 수 있다.

적합성

문서 규약

적합성 요구사항은 설명적 단언과 RFC 2119 용어의 조합으로 표현된다. 이 문서의 규범적 부분에 있는 핵심어 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL”은 RFC 2119에 설명된 대로 해석해야 한다. 그러나 가독성을 위해 이 명세에서는 이러한 단어를 모두 대문자로 표기하지 않는다.

명시적으로 비규범적이라고 표시된 절, 예제 및 참고를 제외한 이 명세의 모든 텍스트는 규범적이다. [RFC2119]

이 명세의 예제는 “예를 들어”라는 말로 시작하거나 다음과 같이 class="example"을 사용하여 규범적 텍스트와 구분한다.

이는 정보 제공용 예제의 예이다.

정보 제공용 참고는 “참고”라는 말로 시작하며 다음과 같이 class="note"를 사용하여 규범적 텍스트와 구분한다.

참고, 이는 정보 제공용 참고이다.

색인

이 명세에서 정의하는 용어

참조로 정의되는 용어

참고 문헌

규범적 참고 문헌

[DOM]
Anne van Kesteren. DOM 표준. 현행 표준. URL: https://dom.spec.whatwg.org/
[HR-TIME-3]
Yoav Weiss. 고해상도 시간. URL: https://w3c.github.io/hr-time/
[HTML]
Anne van Kesteren; 외. HTML 표준. 현행 표준. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 표준. 현행 표준. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. 요구사항 수준을 나타내기 위해 RFC에서 사용하는 핵심어. 1997년 3월. 현행 최선의 관행. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 표준. 현행 표준. URL: https://webidl.spec.whatwg.org/

IDL 색인

[Exposed=Window]
interface AutofillEvent : Event {
  constructor(DOMString type, optional AutofillEventInit eventInitDict = {});
  readonly attribute FrozenArray<AutofillValueEntry> autofillValues;
  readonly attribute RefillCallback? refill;
};

callback RefillCallback = Promise<undefined> ();

dictionary AutofillEventInit : EventInit {
  sequence<AutofillValueEntry> autofillValues = [];
  boolean allowRefill = true;
};

typedef sequence<any> AutofillValueEntry;
// AutofillValueEntry는 [HTMLElement, DOMString]의 튜플이다
// 첫 번째 요소는 양식 컨트롤이고 두 번째 요소는 입력할 값이다