Ortak bileşenler (örn. <div>)

<div> gibi tüm yerleşik tarayıcı bileşenleri bazı ortak prop’ları ve olayları destekler.


Referans

Ortak bileşenler (örn. <div>)

<div className="wrapper">Herhangi bir içerik</div>

Aşağıda daha fazla örnek bulabilirsiniz.

Prop’lar

Şu özel React prop’ları tüm yerleşik bileşenlerde desteklenir:

  • children: Bir React düğümü (bir eleman, bir string, bir sayı, bir portal, null, undefined ve boolean’lar gibi boş bir düğüm, veya diğer React düğümlerinden bir dizi). Bileşenin içeriğini belirtir. JSX kullandığınızda, children prop’unu genellikle etiketleri iç içe <div><span /></div> gibi yerleştirerek üstü kapalı olarak belirteceksiniz.

  • dangerouslySetInnerHTML: İçinde saf bir HTML string’i bulunan { __html: '<p>herhangi bir html</p>' } biçiminde bir nesne. DOM düğümünün innerHTML özelliğini geçersiz kılar ve içeriye verilen HTML’i gösterir. Bunu kullanırken son derece dikkatli olmalısınız! Eğer içteki HTML güvenilir değilse (mesela kullanıcı verisine dayanan bir şeyse), bir XSS riski ortaya çıkarırsınız. dangerouslySetInnerHTML kullanımıyla ilgili daha fazlasını okuyun.

  • ref: useRef veya createRef’ten bir ref nesnesi, veya ref callback fonksiyonu, veya eski sürüm ref’leri için bir string. Bu düğümde ref’iniz DOM elemanıyla doldurulacaktır. DOM’u ref’lerle manipüle etmeyle ilgili daha fazlasını okuyun.

  • suppressContentEditableWarning: Bir boolean. Eğer true ise, hem children hem de contentEditable={true} prop’larına sahip olan elemanlarda (ki bunlar normalde birlikte çalışmazlar) React’ın gösterdiği uyarıları baskılar. Bunu, contentEditable içeriğini manuel olarak yöneten bir metin girdisi kütüphanesi geliştiriyorsanız kullanın.

  • suppressHydrationWarning: Bir boolean. Eğer sunucu taraflı render’lama kullanıyorsanız, sunucu ve istemci farklı içerikleri render ettiğinde normalde bir uyarı görürsünüz. Bazı ender durumlarda (zaman damgası gibi) ise birebir eşleşmeyi sağlamak çok zor veya imkansızdır. Eğer suppressHydrationWarning’i true olarak ayarlarsanız, React o elemanın içeriği ve niteliklerindeki yanlış eşleşmelerle ilgili bir uyarı vermeyecektir. Yalnızca bir kademe derinde çalışır ve bir kaçış yolu olarak kullanılması amaçlanmıştır. Gereğinden fazla kullanmayınız. Hydration hatalarını baskılamayla ilgili daha fazlasını okuyun.

  • style: CSS biçimlerini taşıyan bir nesne, örneğin { fontWeight: 'bold', margin: 20 }. DOM’un style özelliğine benzer olarak, CSS özellik isimleri camelCase olarak yazılmalıdır, örneğin font-weight yerine fontWeight. Değerleri string veya sayı olarak verebilirsiniz. width: 100 şeklinde bir sayı verdiğinizde, eğer birimsiz özellik değilse, React bu sayıya otomatik olarak px (“piksel”)‘i ekler. style’ı yalnızca, biçim değerlerini önceden bilmediğiniz dinamik biçimler için kullanmanızı tavsiye ediyoruz. Diğer durumlarda ise className ile düz CSS sınıfları uygulamak daha verimli. className and style ile ilgili daha fazlasını okuyun.

Şu standart DOM prop’ları da tüm yerleşik bileşenlerde desteklenir:

Prop olarak özel nitelikler de verebilirsiniz, örneğin ozelprop="herhangiBirDeger". Bu, üçüncü parti kütüphaneleri entegre ederken işinize yarayabilir. Özel nitelik isimlerinin küçük harflerle yazılması ve on ile başlamaması gerekmektedir. Değer bir stringe dönüştürülecek. Eğer null veya undefined verirseniz bu özel nitelik kaldırılacaktır.

Şu olaylar yalnızca <form> elemanlarında çalışır:

Şu olaylar yalnızca <dialog> elemanlarında çalışır. Tarayıcı olaylarının aksine, bunlar React’ta kabarırlar:

Şu olaylar yalnızca <details> elemanlarında çalışır. Tarayıcı olaylarının aksine, bunlar React’ta kabarırlar:

Şu olaylar <img>, <iframe>, <object>, <embed>, <link>, ve SVG <image> elemanlarında çalışır. Tarayıcı olaylarının aksine, bunlar React’ta kabarırlar:

Şu olaylar <audio> ve <video> gibi kaynaklarda çalışır. Tarayıcı olaylarının aksine, bunlar React’ta kabarırlar:

Uyarılar

  • Aynı anda hem children hem de dangerouslySetInnerHTML kullanamazsınız.
  • Bazı olaylar (onAbort ve onLoad gibi) tarayıcıda kabarmaz ama React’ta kabarır.

ref callback fonksiyonu

ref niteliğine, bir ref nesnesi yerine (useRef tarafından döndürülen gibi) bir fonksiyon verebilirsiniz.

<div ref={(node) => console.log(node)} />

ref callback’inin örnek kullanımına bakınız.

React, <div> DOM düğümü ekrana eklendiğinde, ref callback’inizi argümanda DOM düğümü (node) olacak şekilde çağıracaktır. Bu <div> DOM düğümü kaldırıldığında ise React, ref callback’inizi null ile çağıracaktır.

Ayrıca React, siz farklı bir ref callback’i verir vermez ref callback’inizi çağıracaktır. Yukarıdaki örnekteki (node) => { ... }, her render’da farklı bir fonksiyondur. Bileşeniniz tekrar render edildiğinde önceki fonksiyon argümanında null ile, sonraki fonkisyon ise DOM düğümüyle çağırılacaktır.

Parametreler

  • node: Bir DOM düğümü veya null. React, ref bağlanınca size DOM düğümü, bağlantı kesilince ise null verecektir. Eğer ki her render’da ref callback’i için aynı fonksiyon referansını vermezseniz, callback’in geçici olarak bağlantısı kesilecek ve bileşenin her yeniden render’lanması sırasında tekrar bağlanacaktır.

Döndürülenler

ref callback’i herhangi bir şey geri döndürmez.


React olay nesnesi

Olay yöneticileriniz bir React olay nesnesi alacaktır. Buna bazen “sentetik olay” da denir.

<button onClick={e => {
console.log(e); // React olay nesnesi
}} />

Altta yatan DOM olaylarıyla aynı standartlara uyar ama bazı tarayıcı tutarsızlıklarına çözüm sağlar.

Bazı React olayları tarayıcının yerel olaylarıyla birebir eşleşmez. Örneğin onMouseLeave’de e.nativeEvent bir mouseout olayına işaret edecektir. Birebir eşleşme açık API’ye dahil değildir ve gelecekte değişebilir. Eğer herhangi bir sebeple altta yatan tarayıcı olayına ihtiyacınız varsa e.nativeEvent’ten ulaşabilirsiniz.

Özellikler

React olay nesneleri bazı standart Event özelliklerini uygular:

  • bubbles: Bir boolean. Olayın DOM boyunca kabarıp kabarmadığını döndürür.
  • cancelable: Bir boolean. Olayın iptal edip edilemediğini döndürür.
  • currentTarget: Bir DOM düğümü. Mevcut yöneticinin React ağacında bağlı olduğu düğümü döndürür.
  • defaultPrevented: Bir boolean. preventDefault’un çağırılıp çağırılmadığını döndürür.
  • eventPhase: Bir sayı. Olayın halihazırda bulunduğu aşamayı döndürür.
  • isTrusted: Bir boolean. Olayın kullanıcı tarafından oluşturulup oluşturulmadığını döndürür.
  • target: Bir DOM düğümü. Olayın gerçekleştiği düğümü döndürür (uzak bir alt eleman olabilir).
  • timeStamp: Bir sayı. Olayın gerçekleştiği zamanı döndürür.

Ek olarak, React olay nesneleri şu özellikleri de sağlar:

  • nativeEvent: Bir DOM Event’i. Orijinal tarayıcı olay nesnesidir.

Metotlar

React olay nesneleri bazı standart Event metotlarını uygular:

Ek olarak, React olay nesneleri şu metotları da sağlar:

  • isDefaultPrevented(): preventDefault’un çağırılıp çağırılmadığını gösteren bir boolean döndürür.
  • isPropagationStopped(): stopPropagation’ın çağırılıp çağırılmadığını gösteren bir boolean döndürür.
  • persist(): React DOM’uyla kullanılmaz. React Native’de, olaydan sonra olayın özelliklerine ulaşmak için bunu çağırın.
  • isPersistent(): React DOM’uyla kullanılmaz. React Native’de, persist’in çağırılıp çağırılmadığını döndürür.

Uyarılar

  • currentTarget, eventPhase, target, ve type’ın değerleri React kodunuzun beklediği değerleri yansıtır. React aslında olay yöneticilerini kökte bağlar ama bu React’ın olay nesnelerine yansıtılmaz. Örneğin, e.currentTarget altta yatan e.nativeEvent.currentTarget ile aynı olmayabilir. Polyfill yapılmış olaylarda e.type (React olay tipi), e.nativeEvent.type’tan (altta yatan tip) farklı olabilir.

AnimationEvent yönetici fonksiyonu

CSS animasyonu olayları için bir olay yöneticisi tipi.

<div
onAnimationStart={e => console.log('onAnimationStart')}
onAnimationIteration={e => console.log('onAnimationIteration')}
onAnimationEnd={e => console.log('onAnimationEnd')}
/>

Parametreler


ClipboardEvent yönetici fonksiyonu

Clipboard API olayları için bir olay yöneticisi tipi.

<input
onCopy={e => console.log('onCopy')}
onCut={e => console.log('onCut')}
onPaste={e => console.log('onPaste')}
/>

Parametreler


CompositionEvent yönetici fonksiyonu

Girdi metodu düzenleyicisi (IME) olayları için bir olay yöneticisi tipi.

<input
onCompositionStart={e => console.log('onCompositionStart')}
onCompositionUpdate={e => console.log('onCompositionUpdate')}
onCompositionEnd={e => console.log('onCompositionEnd')}
/>

Parametreler


DragEvent yönetici fonksiyonu

HTML Sürükle ve Bırak API’si olayları için bir olay yöneticisi tipi.

<>
<div
draggable={true}
onDragStart={e => console.log('onDragStart')}
onDragEnd={e => console.log('onDragEnd')}
>
Sürükleme kaynağı
</div>

<div
onDragEnter={e => console.log('onDragEnter')}
onDragLeave={e => console.log('onDragLeave')}
onDragOver={e => { e.preventDefault(); console.log('onDragOver'); }}
onDrop={e => console.log('onDrop')}
>
Bırakma hedefi
</div>
</>

Parametreler


FocusEvent yönetici fonksiyonu

Odaklanma olayları için bir olay yöneticisi tipi.

<input
onFocus={e => console.log('onFocus')}
onBlur={e => console.log('onBlur')}
/>

Şu örneğe göz atın.

Parametreler


Event yönetici fonksiyonu

Genel olaylar için bir olay yöneticisi tipi.

Parametreler


InputEvent yönetici fonksiyonu

onBeforeInput olayı için bir olay yöneticisi tipi.

<input onBeforeInput={e => console.log('onBeforeInput')} />

Parametreler


KeyboardEvent yönetici fonksiyonu

Klavye olayları için bir olay yöneticisi tipi.

<input
onKeyDown={e => console.log('onKeyDown')}
onKeyUp={e => console.log('onKeyUp')}
/>

Şu örneğe göz atın.

Parametreler


MouseEvent yönetici fonksiyonu

Fare olayları için bir olay yöneticisi tipi.

<div
onClick={e => console.log('onClick')}
onMouseEnter={e => console.log('onMouseEnter')}
onMouseOver={e => console.log('onMouseOver')}
onMouseDown={e => console.log('onMouseDown')}
onMouseUp={e => console.log('onMouseUp')}
onMouseLeave={e => console.log('onMouseLeave')}
/>

Şu örneğe göz atın.

Parametreler


PointerEvent yönetici fonksiyonu

İmleç olayları için bir olay yöneticisi tipi.

<div
onPointerEnter={e => console.log('onPointerEnter')}
onPointerMove={e => console.log('onPointerMove')}
onPointerDown={e => console.log('onPointerDown')}
onPointerUp={e => console.log('onPointerUp')}
onPointerLeave={e => console.log('onPointerLeave')}
/>

Şu örneğe göz atın.

Parametreler


TouchEvent yönetici fonksiyonu

Dokunma olayları için bir olay yöneticisi tipi.

<div
onTouchStart={e => console.log('onTouchStart')}
onTouchMove={e => console.log('onTouchMove')}
onTouchEnd={e => console.log('onTouchEnd')}
onTouchCancel={e => console.log('onTouchCancel')}
/>

Parametreler


TransitionEvent yönetici fonksiyonu

CSS geçiş olayları için bir olay yöneticisi tipi.

<div
onTransitionEnd={e => console.log('onTransitionEnd')}
/>

Parametreler


UIEvent yönetici fonksiyonu

Genel UI olayları için bir olay yöneticisi tipi.

<div
onScroll={e => console.log('onScroll')}
/>

Parametreler


WheelEvent yönetici fonksiyonu

onWheel olayı için bir olay yöneticisi tipi.

<div
onWheel={e => console.log('onWheel')}
/>

Parametreler


Kullanım

CSS stillerinin uygulanması

React’ta bir CSS sınıfını className kullanarak belirtirsiniz. HTML’deki class niteliği gibi çalışır:

<img className="avatar" />

Sonra bu sınıf için CSS kurallarını ayrı bir CSS dosyasına yazarsınız:

/* CSS dosyanız */
.avatar {
border-radius: 50%;
}

React, CSS dosyalarını nasıl ekleyeceğinizle ilgili sıkı kurallar koymaz. En basit yol, HTML’inize bir<link> etiketi eklemektir. Eğer bir derleme aracı veya bir çatı kullanırsanız, projenize nasıl CSS dosyası ekleyeceğinizi öğrenmek için ilgili dokümantasyona danışabilirsiniz.

Bazen stil değerleri veriye bağlıdır. Dinamik bir şekilde stillendirmek için style niteliğini kullanın:

<img
className="avatar"
style={{
width: user.imageSize,
height: user.imageSize
}}
/>

Yukarıdaki örnekteki style={{}} özel bir söz dizimi değil, style={ } JSX süslü parantezleri içinde yer alan sıradan bir {} nesnesidir. Stilleriniz JavaScript değişkenlerine bağlı olduğunda yalnızca style kullanmanızı öneriyoruz.

export default function Avatar({ user }) {
  return (
    <img
      src={user.imageUrl}
      alt={user.name + ' profil fotoğrafı'}
      className="avatar"
      style={{
        width: user.imageSize,
        height: user.imageSize
      }}
    />
  );
}

Derinlemesine İnceleme

Birden fazla CSS sınıfı koşulsal olarak nasıl uygulanır?

CSS sınıflarını koşulsal olarak uygulamak için className string’ini JavaScript’i kullanarak kendiniz üretmeniz gerekiyor.

Örneğin, className={'row ' + (isSelected ? 'selected': '')}, isSelected’ın true olup olmamasına göre className="row" veya className="row selected" üretecektir.

Bunu daha okunaklı hale getirmek için classnames gibi minik yardımcı bir kütüphane kullanabilirsiniz:

import cn from 'classnames';

function Row({ isSelected }) {
return (
<div className={cn('row', isSelected && 'selected')}>
...
</div>
);
}

Özellikle birden fazla koşulsal sınıfınız varsa kullanışlı oluyor:

import cn from 'classnames';

function Row({ isSelected, size }) {
return (
<div className={cn('row', {
selected: isSelected,
large: size === 'large',
small: size === 'small',
})}>
...
</div>
);
}

Bir DOM düğümünü ref ile manipüle etme

Bazı durumlarda tarayıcıdaki DOM düğümünün JSX’teki bir etiket ile ilişkilendirilmesine ihtiyaç duyacaksınız. Örneğin, eğer bir butona tıkladığınızda bir <input>’a odaklanmak istiyorsanız, tarayıcıdaki <input> DOM düğümünde focus()’u çağırmanız gerekiyor.

Bir etikette, tarayıcıdaki DOM düğümünü elde etmek için, bir ref tanımlayın ve bunu, o etikete ref niteliği olarak verin:

import { useRef } from 'react';

export default function Form() {
const inputRef = useRef(null);
// ...
return (
<input ref={inputRef} />
// ...

React, DOM düğümü ekrana render edildikten sonra onu inputRef.current’ın içine koyacaktır.

import { useRef } from 'react';

export default function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        Girdiye odaklan
      </button>
    </>
  );
}

DOM’u ref’lerle manipüle etme hakkında daha fazlasını okuyun ve daha fazla örneğe göz atın.

Daha ileri düzey kullanım durumları için ref niteliği ayrıca bir callback fonksiyonu da kabul eder.


İç HTML’i tehlikeli bir şekilde ayarlama

Bir elemana şu şekilde düz bir HTML string’i verebilirsiniz:

const markup = { __html: '<p>düz bir html içeriği</p>' };
return <div dangerouslySetInnerHTML={markup} />;

Bu tehlikelidir. Altta yatan DOM’un innerHTML özelliğinde olduğu gibi, son derece dikkatli kullanmanız gerekir. Eğer ki biçimlendirme (markup) çok güvenilir bir kaynaktan gelmiyorsa, bu şekilde bir XSS zayıflığı oluşturmak gereksizdir.

Örneğin, eğer Markdown’ı HTML’e dönüştüren bir Markdown kütüphanesi kullanıyorsanız, ayrıştırıcısında herhangi bir hata olmadığına güveniyorsanız ve kullanıcı yalnızca kendi girdisini görüyorsa, sonuçta oluşan HTML’i şöyle görüntüleyebilirsiniz:

import { Remarkable } from 'remarkable';

const md = new Remarkable();

function renderMarkdownToHTML(markdown) {
  // Bu yöntem, YALNIZCA sonuçta oluşan HTML
  // aynı kullanıcıya gösterildiği ve Markdown 
  // ayrıştırıcısında hata olmadığına
  // emin olduğunuz için güvenlidir.
  const renderedHTML = md.render(markdown);
  return {__html: renderedHTML};
}

export default function MarkdownPreview({ markdown }) {
  const markup = renderMarkdownToHTML(markdown);
  return <div dangerouslySetInnerHTML={markup} />;
}

{__html} nesnesi, yukarıdaki örnekte renderMarkdownToHTML olduğu gibi, HTML’nin oluşturulduğu yere mümkün olduğunca yakın oluşturulmalıdır. Bu, kodunuzda kullanılan tüm ham HTML’nin açıkça bu şekilde işaretlenmesini ve yalnızca HTML içermesini beklediğiniz değişkenlerin dangerouslySetInnerHTML’ye iletilmesini sağlar. Nesnenin satır içi olarak <div dangerouslySetInnerHTML={{__html: markup}} /> gibi oluşturulması önerilmez.

Gelişigüzel HTML’i render etmenin neden tehlikeli olduğunu görmek için yukarıdaki kod yerine şunu koyun:

const post = {
// Bu içeriğin veritabanında saklandığını hayal edelim.
content: `<img src="" onerror='alert("hacklendiniz!!!")'>`
};

export default function MarkdownPreview() {
// 🔴 GÜVENLİK AÇIĞI: dangerouslySetInnerHTML'e güvenilir olmayan girdi veriyorsunuz
const markup = { __html: post.content };
return <div dangerouslySetInnerHTML={markup} />;
}

HTML’de gömülü olan kod çalışacak. Bir hacker, bu güvenlik açığını kullanıcı bilgilerini çalmak veya kendi çıkarları için kullanabilir. dangerouslySetInnerHTML’i yalnızca güvenilir ve temizlenmiş verilerle kullanın.


Fare olaylarını yönetme

Bu örnek bazı yaygın fare olaylarını ve ne zaman çalıştıklarını gösteriyor.

export default function MouseExample() {
  return (
    <div
      onMouseEnter={e => console.log('onMouseEnter (üst eleman)')}
      onMouseLeave={e => console.log('onMouseLeave (üst eleman)')}
    >
      <button
        onClick={e => console.log('onClick (birinci buton)')}
        onMouseDown={e => console.log('onMouseDown (birinci buton)')}
        onMouseEnter={e => console.log('onMouseEnter (birinci buton)')}
        onMouseLeave={e => console.log('onMouseLeave (birinci buton)')}
        onMouseOver={e => console.log('onMouseOver (birinci buton)')}
        onMouseUp={e => console.log('onMouseUp (birinci buton)')}
      >
        Birinci buton
      </button>
      <button
        onClick={e => console.log('onClick (ikinci buton)')}
        onMouseDown={e => console.log('onMouseDown (ikinci buton)')}
        onMouseEnter={e => console.log('onMouseEnter (ikinci buton)')}
        onMouseLeave={e => console.log('onMouseLeave (ikinci buton)')}
        onMouseOver={e => console.log('onMouseOver (ikinci buton)')}
        onMouseUp={e => console.log('onMouseUp (ikinci buton)')}
      >
        İkinci buton
      </button>
    </div>
  );
}


İmleç olaylarını yönetme

Bu örnek bazı yaygın imleç olayarını ve ne zaman çalıştıklarını gösteriyor.

export default function PointerExample() {
  return (
    <div
      onPointerEnter={e => console.log('onPointerEnter (üst eleman)')}
      onPointerLeave={e => console.log('onPointerLeave (üst eleman)')}
      style={{ padding: 20, backgroundColor: '#ddd' }}
    >
      <div
        onPointerDown={e => console.log('onPointerDown (birinci alt eleman)')}
        onPointerEnter={e => console.log('onPointerEnter (birinci alt eleman)')}
        onPointerLeave={e => console.log('onPointerLeave (birinci alt eleman)')}
        onPointerMove={e => console.log('onPointerMove (birinci alt eleman)')}
        onPointerUp={e => console.log('onPointerUp (birinci alt eleman)')}
        style={{ padding: 20, backgroundColor: 'lightyellow' }}
      >
        Birinci alt eleman
      </div>
      <div
        onPointerDown={e => console.log('onPointerDown (ikinci alt eleman)')}
        onPointerEnter={e => console.log('onPointerEnter (ikinci alt eleman)')}
        onPointerLeave={e => console.log('onPointerLeave (ikinci alt eleman)')}
        onPointerMove={e => console.log('onPointerMove (ikinci alt eleman)')}
        onPointerUp={e => console.log('onPointerUp (ikinci alt eleman)')}
        style={{ padding: 20, backgroundColor: 'lightblue' }}
      >
        İkinci alt eleman
      </div>
    </div>
  );
}


Odaklanma olaylarını yönetme

Odaklanma olayları React’ta kabarırlar. Odaklanma ve bulandırma olaylarının üst elemanın dışında oluşup oluşmadığını ayırt etmek için currentTarget ve relatedTarget’i kullanabilirsiniz. Aşağıdaki örnek, bir alt elemana veya üst elemana odaklanmanın ve tüm alt ağaca giren veya çıkan odaklanmaların nasıl tespit edileceğini gösteriyor.

export default function FocusExample() {
  return (
    <div
      tabIndex={1}
      onFocus={(e) => {
        if (e.currentTarget === e.target) {
          console.log('üst elemana odaklanıldı');
        } else {
          console.log(e.target.name, 'alt elemanına odaklanıldı');
        }
        if (!e.currentTarget.contains(e.relatedTarget)) {
          // Alt elemanlar arasındaki odağı değiştirirken tetiklenmez
          console.log('odak üst elemana girdi');
        }
      }}
      onBlur={(e) => {
        if (e.currentTarget === e.target) {
          console.log('üst elemandan odak kaldırıldı');
        } else {
          console.log(e.target.name, 'alt elemanından odak kaldırıldı');
        }
        if (!e.currentTarget.contains(e.relatedTarget)) {
          // Alt elemanlar arasındaki odağı değiştirirken tetiklenmez
          console.log('odak üst elemandan çıktı');
        }
      }}
    >
      <label>
        İsim:
        <input name="isim" />
      </label>
      <label>
        Soyisim:
        <input name="soyisim" />
      </label>
    </div>
  );
}


Klavye olaylarını yönetme

Bu örnek bazı yaygın klavye olaylarını ve ne zaman çalıştıklarını gösteriyor.

export default function KeyboardExample() {
  return (
    <label>
      İsim:
      <input
        name="isim"
        onKeyDown={e => console.log('onKeyDown:', e.key, e.code)}
        onKeyUp={e => console.log('onKeyUp:', e.key, e.code)}
      />
    </label>
  );
}