Shadow DOM, Firefox 및 contenteditable

This is more of a short note about some experiments when working with web components that I’m publishing as a reference for future me (or other people that experience the same issue).



저는 바닐라 JS에서 쉽게 사용할 수 있는 Felte 래퍼를 만들기 위해 웹 컴포넌트를 실험해왔습니다. Felte의 기능 중 하나는 브라우저의 기본 입력( input , textarea , select )을 기반으로 하지 않는 사용자 정의 필드 구성 요소를 사용하는 기능입니다. 내가 보여주는 예는 속성이 [contenteditable=“true”] 인 div입니다. 이 실험을 테스트하는 동안 Firefox에서 이상한 동작이 발생하는 것을 발견했습니다. 각 필드를 완벽하게 클릭하고 입력할 수 있지만 키보드만 사용하여 양식을 사용하려고 하면(각 필드로 탭 이동) 포커스가 이동했지만 입력을 시도하면 항상 초점을 맞춘 첫 번째 필드에 텍스트가 추가됩니다.

또 다른 혼란스러운 동작은 요소 자체를 클릭할 때 요소를 입력할 수 있어도 케어가 전혀 표시되지 않는다는 것입니다. 따라서 요소 자체를 편집할 수 있음을 사용자에게 알리는 시각적 신호가 없습니다. 현재 open issue on bugzilla that seems to be exactly this 가 있습니다.

물론 이러한 행동은 용납될 수 없습니다. 특히 양식(및 일반적으로 웹 응용 프로그램)은 키보드 사용자가 액세스할 수 있어야 하기 때문입니다. the demo I was working on가 올바르게 작동하려면 즉각적인 해결책을 찾으러 갔습니다. 몇 가지 조사를 한 후 저에게 더 일관되게 작동하는 솔루션은 렌더링 시 필드에 추가[contenteditable]하지 않고 대신 포커스에 속성을 동적으로 추가하고 흐림 효과를 제거하는 이벤트 리스너를 추가하는 것입니다.

function handleFocus(e) {
  e.target.setAttribute('contenteditable', '');
}

function handleBlur(e) {
  e.target.removeAttribute('contenteditable');
}

// We query the shadowRoot of the element that contains
// our `contenteditable` fields
element.shadowRoot
  .querySelectorAll('div[role="textbox"]')
  .forEach((el) => {
    el.addEventListener('focusin', handleFocus);
    el.addEventListener('focusout', handleBlur);
  });


또는 더 쉽게 재사용할 수 있도록 다음과 같이 동작하는 사용자 지정 요소를 만듭니다.

function handleFocus(e) {
  e.target.setAttribute('contenteditable', '');
}

function handleBlur(e) {
  e.target.removeAttribute('contenteditable');
}

export class MyField extends HTMLElement {
  constructor() {
    super();
    // Make the element focusable
    this.setAttribute('tabindex', '0');
    // Assign a role for assistive technologies
    this.setAttribute('role', 'textbox');
    // Some default styles
    this.style.display = 'block';
    this.style.cursor = 'text';
  }

  connectedCallback() {
    this.addEventListener('focusin', handleFocus);
    this.addEventListener('focusout', handleBlur);
  }

  disconnectedCallback() {
    this.removeEventListener('focusin', handleFocus);
    this.removeEventListener('focusout', handleBlur);
  }
}

customElements.define('my-field', MyField);


이 방법으로 <my-field></my-field>[contenteditable] "div"로 사용할 수 있습니다!

이 기사는 초점이 [contenteditable] 요소에서 올바르게 작동하도록 만드는 것에 대해서만 걱정한다는 점을 명심하십시오. 사용 사례에 따라 이와 같은 작업을 수행할 때 고려해야 할 사항이 더 있습니다.

좋은 웹페이지 즐겨찾기