Block Editor

Editor composing content from discrete blocks.

Meeting notes

We're shipping the new onboarding flow next sprint. Here's what changed and why.

html

<div class="editor editor--comfortable" style="--accent:#BFD9F2;">
  <div class="editor__block">
    <span class="editor__handle" aria-hidden="true">&#10247;</span>
    <h2 class="editor__heading">Meeting notes</h2>
  </div>
  <div class="editor__block">
    <span class="editor__handle" aria-hidden="true">&#10247;</span>
    <p class="editor__body">We&#39;re shipping the new onboarding flow next sprint. Here&#39;s what changed and why.</p>
  </div>
  <button type="button" class="editor__add">
    <svg viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"><path d="M8 2v12M2 8h12" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
    Add block
  </button>
</div>
<style>
.editor { font: 15px/1.5 system-ui, sans-serif; color: #241430; background: #FAF7F2; border: 1.5px solid #24143022; border-radius: 10px; padding: 6px; max-width: 420px; }
.editor__block { display: flex; align-items: flex-start; gap: 8px; padding: 10px; border-radius: 6px; }
.editor__block:hover { background: #24143008; }
.editor--compact .editor__block { padding: 4px 10px; }
.editor__handle { color: #24143055; padding-top: 3px; cursor: grab; user-select: none; }
.editor__heading { margin: 0; font-size: 20px; font-weight: 700; }
.editor__body { margin: 0; color: #241430cc; }
.editor--compact .editor__heading { font-size: 17px; }
.editor__add { display: inline-flex; align-items: center; gap: 6px; margin: 6px 4px 4px; padding: 6px 10px; border-radius: 6px; border: 1.5px dashed var(--accent); background: transparent; color: var(--accent); font: 500 13px system-ui, sans-serif; cursor: pointer; }
.editor__add:hover, .editor__add:focus-visible { background: color-mix(in srgb, var(--accent) 14%, transparent); outline: none; }
</style>

tailwind

<div style="--accent:#BFD9F2;" class="editor-tw editor-tw--comfortable font-sans text-[15px] text-[#241430] bg-[#FAF7F2] border-[1.5px] border-[#24143022] rounded-[10px] p-1.5 max-w-[420px]">
  <div class="editor-tw__block flex items-start gap-2 p-2.5 rounded-md hover:bg-[#24143008]">
    <span class="text-[#24143055] pt-0.5 cursor-grab select-none" aria-hidden="true">&#10247;</span>
    <h2 class="m-0 text-xl font-bold">Meeting notes</h2>
  </div>
  <div class="editor-tw__block flex items-start gap-2 p-2.5 rounded-md hover:bg-[#24143008]">
    <span class="text-[#24143055] pt-0.5 cursor-grab select-none" aria-hidden="true">&#10247;</span>
    <p class="m-0 text-[#241430cc]">We&#39;re shipping the new onboarding flow next sprint. Here&#39;s what changed and why.</p>
  </div>
  <button type="button" class="inline-flex items-center gap-1.5 m-1.5 px-2.5 py-1.5 rounded-md border-[1.5px] border-dashed bg-transparent text-sm font-medium" style="border-color:#BFD9F2;color:#BFD9F2">
    <svg viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"><path d="M8 2v12M2 8h12" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>
    Add block
  </button>
</div>
<style>
.editor-tw--compact .editor-tw__block { padding: 4px 10px; }
.editor-tw--compact h2 { font-size: 17px; }
</style>

react

export function BlockEditor({
  heading = "Meeting notes",
  body = "We&#39;re shipping the new onboarding flow next sprint. Here&#39;s what changed and why.",
  accent = "#BFD9F2",
  showHandles = true,
  density = "comfortable",
}) {
  const compact = density === "compact";
  return (
    <div style={{ fontFamily: "system-ui, sans-serif", fontSize: 15, lineHeight: 1.5, color: "#241430",
      background: "#FAF7F2", border: "1.5px solid #24143022", borderRadius: 10, padding: 6, maxWidth: 420 }}>
      <div style={{ display: "flex", alignItems: "flex-start", gap: 8, padding: compact ? "4px 10px" : 10, borderRadius: 6 }}>
        {showHandles && <span aria-hidden="true" style={{ color: "#24143055", paddingTop: 3, cursor: "grab" }}>&#10247;</span>}
        <h2 style={{ margin: 0, fontSize: compact ? 17 : 20, fontWeight: 700 }}>{heading}</h2>
      </div>
      <div style={{ display: "flex", alignItems: "flex-start", gap: 8, padding: compact ? "4px 10px" : 10, borderRadius: 6 }}>
        {showHandles && <span aria-hidden="true" style={{ color: "#24143055", paddingTop: 3, cursor: "grab" }}>&#10247;</span>}
        <p style={{ margin: 0, color: "#241430cc" }}>{body}</p>
      </div>
      <button type="button" style={{ display: "inline-flex", alignItems: "center", gap: 6, margin: "6px 4px 4px",
        padding: "6px 10px", borderRadius: 6, border: `1.5px dashed ${accent}`, background: "transparent",
        color: accent, fontSize: 13, fontWeight: 500, cursor: "pointer" }}>
        <svg viewBox="0 0 16 16" width="14" height="14" aria-hidden="true"><path d="M8 2v12M2 8h12" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" /></svg>
        Add block
      </button>
    </div>
  );
}