WebDev ViewSplitterBar Component

two panels with draggable splitter bar and bottom resizer

1.0 Contents

A W3C custom element (<view-splitter-bar>) that displays two adjacent panels separated by a draggable vertical splitter bar and a draggable horizontal resizer along the bottom edge. Dragging the splitter redistributes width between panels without changing total component width. Dragging the resizer changes the height of both panels together. Clicking either panel shifts the split by one step.

2.0 Files

ViewSplitterBarComponent/
  js/ViewSplitterBar.js          component definition
  css/ViewSplitterBar.css        host-page placement helpers
  ViewSplitterBarComponent.html  demo / test page
  SpecSplitterBarComponent.md    design specification

3.0 Setup

Load the component script (and optionally Prism for syntax highlighting):
<link rel="stylesheet" href="../css/prism.css">
<link rel="stylesheet" href="css/ViewSplitterBar.css">
<script src="../js/prism.js" defer></script>
<script src="js/ViewSplitterBar.js" defer></script>
The containing page should define --light and --dark CSS custom properties:
:root {
  --light: #f0f0f0;
  --dark:  #333;
}

4.0 Usage


/* --------------------------------------------------------------- */
#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>

int main() {
    std::vector<int> v = {5, 3, 8, 1, 9, 2, 7};

    std::sort(v.begin(), v.end());

    int sum = std::accumulate(v.begin(), v.end(), 0);
    double avg = static_cast<double>(sum) / v.size();

    std::cout << "sorted: ";
    for (int x : v) std::cout << x << " ";
    std::cout << "\nsum = " << sum
              << "  avg = " << avg << "\n";
    return 0;
}            
          

/* --------------------------------------------------------------- */
fn main() {
    let mut v = vec![5, 3, 8, 1, 9, 2, 7];

    v.sort();

    let sum: i32 = v.iter().sum();
    let avg = sum as f64 / v.len() as f64;

    print!("sorted: ");
    for x in &v { print!("{x} "); }
    println!("\nsum = {sum}  avg = {avg}");
}
          

Plain text

<view-splitter-bar width="60rem" height="16rem" left-ratio="0.5">
  <pre slot="left">Left panel content.</pre>
  <pre slot="right">Right panel content.</pre>
</view-splitter-bar>

Prism syntax highlighting

Supply a <pre><code class="language-..."> in each named slot:
<view-splitter-bar width="70rem" height="20rem" highlight="prism">
  <pre slot="left"><code class="language-cpp">
int main() { return 0; }
  </code></pre>
  <pre slot="right"><code class="language-rust">
fn main() {}
  </code></pre>
</view-splitter-bar>

5.0 Attributes

AttributeDefaultDescription
widthautoTotal component width (px or rem)
heightautoInitial panel height (px or rem); draggable after render
left-ratio0.5Initial fraction of total width given to the left panel
bar-width6pxWidth of the vertical splitter and height of the bottom resizer
bar-color#888Color of both the splitter and the resizer
bg-colorvar(--light)Background of both panels
colorvar(--dark)Text color of both panels
overflow-xautoHorizontal overflow: auto, scroll, or hidden
code-padding0.75rem 1remPadding inside each panel
highlight(none)Set to prism to enable Prism.js syntax highlighting
step-px40Pixels transferred per panel click
min-panel-px120Minimum width in pixels for either panel
min-height-px80Minimum container height in pixels when dragging the resizer

6.0 Interaction

  • Drag splitter - redistributes width between panels; total width stays fixed.
  • Drag resizer - changes height of both panels; width is unaffected.
  • Click left panel - transfers step-px pixels from right to left.
  • Click right panel - transfers step-px pixels from left to right.

7.0 Inline Style Notes

  • font-size cascades through the shadow DOM boundary; set it on the element directly.
  • height is managed as an explicit pixel value on the inner container. Use the height attribute to set an initial value; after the first resizer drag the attribute is no longer consulted.