Basic Input
A labelled text input with helper text wired to it via aria-describedby.
6 個のフレームワーク初級
A markdown field with bold, italic and link buttons that wrap the selection.
<!--
A markdown toolbar, not a rich-text editor: every button wraps the selection
in plain syntax the textarea can hold. That is a deliberate ceiling - the
moment you want real bold you need contenteditable, and you have signed up for
a different component entirely.
Three details that make it a toolbar rather than three loose buttons:
- role="toolbar" + aria-controls, so it announces as belonging to the field
- each button has an aria-label; the glyphs are aria-hidden
- setSelectionRange after the edit, so focus lands back where you were typing
with the wrapped text still selected
-->
<div class="tb-field">
<label class="tb-field__label" for="tb-field-body">Description</label>
<div class="tb-field__box">
<div class="tb-field__toolbar" role="toolbar" aria-label="Formatting" aria-controls="tb-field-body">
<button class="tb-field__btn" type="button" data-wrap="**" aria-label="Bold">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
<path d="M6 4h8a4 4 0 0 1 0 8H6zM6 12h9a4 4 0 0 1 0 8H6z" />
</svg>
</button>
<button class="tb-field__btn" type="button" data-wrap="_" aria-label="Italic">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
<path d="M19 4h-9M14 20H5M15 4 9 20" />
</svg>
</button>
<button class="tb-field__btn" type="button" data-link aria-label="Insert link">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
<path d="M10 13a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1 1" />
<path d="M14 11a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1-1" />
</svg>
</button>
</div>
<textarea
class="tb-field__input"
id="tb-field-body"
name="body"
rows="5"
placeholder="Markdown is supported."
aria-describedby="tb-field-body-help"
></textarea>
</div>
<p class="tb-field__help" id="tb-field-body-help">Select text, then choose a format.</p>
</div>
<script>
document.querySelectorAll('.tb-field').forEach(function (root) {
var input = root.querySelector('.tb-field__input');
function surround(before, after) {
var start = input.selectionStart;
var end = input.selectionEnd;
var selected = input.value.slice(start, end);
input.value =
input.value.slice(0, start) + before + selected + after + input.value.slice(end);
// Focus first: setSelectionRange on an unfocused textarea is a no-op in
// some browsers, and the caret would land at the end.
input.focus();
input.setSelectionRange(start + before.length, start + before.length + selected.length);
}
root.querySelectorAll('.tb-field__btn').forEach(function (btn) {
btn.addEventListener('click', function () {
var wrap = btn.getAttribute('data-wrap');
if (wrap) surround(wrap, wrap);
else surround('[', '](https://)');
});
});
});
</script>| Prop | 型 | デフォルト | 説明 |
|---|---|---|---|
label必須 | string | - | 読み込み中に読み上げられるアクセシブルなラベル。 |
value必須 | string | - | 指標の現在値。フォーマット済みの文字列を渡します。 |
disabled | boolean | false | 操作を無効にし、コントロールを淡色表示にします。 |
className | string | - | ルート要素にマージされる追加クラス。 |
A markdown toolbar, not a rich-text editor: every button wraps the selection in plain syntax a textarea can hold. That ceiling is deliberate - the moment you want real bold you need `contenteditable` and a different component. Three details make it a toolbar rather than three loose buttons: `role="toolbar"` with `aria-controls` so it announces as belonging to the field, an `aria-label` on every button with the glyphs `aria-hidden`, and `setSelectionRange` after the edit so focus returns to the field with the wrapped text still selected. The React variants restore that selection inside `requestAnimationFrame` because the DOM value only updates on the next render - without the wait the caret jumps to the end. Add tools by extending `TOOLS`.