<h1>CSS Writing Modes example with range Inputs</h1>
<p class="intro">This demo showcases all CSS writing modes applied to range inputs and their text displaying the value. the DOM structure is the same for each input.</p>

<div class="demo-container">
  <div class="range-container">
    <h3>horizontal-tb</h3>
    <div class="input-wrapper">
      <div class="horizontal-tb-wrapper direction-wrapper">
        <input type="range" class="horizontal-tb" value="80" min="0" max="100">
        <div class="value-display">Value: 80</div>
      </div>
    </div>
    <p>Standard horizontal orientation. Content flows horizontally from top to bottom (tb = top to bottom).</p>
  </div>

  <div class="range-container">
    <h3>vertical-lr</h3>
    <div class="input-wrapper">
      <div class="vertical-lr-wrapper direction-wrapper">
        <input type="range" class="vertical-lr" value="80" min="0" max="100">
        <div class="value-display">Value: 80</div>
      </div>
    </div>
    <p>Content flows vertically from left to right (lr = left to right). Characters remain upright.</p>
  </div>

  <div class="range-container">
    <h3>vertical-rl</h3>
    <div class="input-wrapper">
      <div class="vertical-rl-wrapper direction-wrapper">
        <input type="range" class="vertical-rl" value="80" min="0" max="100">
        <div class="value-display">Value: 80</div>
      </div>
    </div>
    <p>Content flows vertically from right to left (rl = right to left). Characters remain upright.</p>
  </div>

  <div class="range-container">
    <h3>sideways-lr</h3>
    <div class="input-wrapper">
      <div class="sideways-lr-wrapper direction-wrapper">
        <input type="range" class="sideways-lr" value="80" min="0" max="100">
        <div class="value-display">Value: 80</div>
      </div>
    </div>
    <p>Content flows vertically from left to right, but characters are rotated 90° clockwise.</p>
    <div class="browser-support">Limited, part of interop 2025</div>
  </div>

  <div class="range-container">
    <h3>sideways-rl</h3>
    <div class="input-wrapper">
      <div class="sideways-rl-wrapper direction-wrapper">
        <input type="range" class="sideways-rl" value="80" min="0" max="100">
        <div class="value-display">Value: 80</div>
      </div>
    </div>
    <p>Content flows vertically from right to left, but characters are rotated 90° clockwise.</p>
    <div class="browser-support">Limited, part of interop 2025</div>
  </div>
</div>
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap");

@layer presentation, writing-modes;

:root {
  --color-primary: #3498db;
  --color-primary-dark: #2980b9;
  --color-text: #2c3e50;
  --color-text-light: #7f8c8d;
  --color-warning: #e74c3c;
  --color-background: #f5f7fa;
  --color-card: #ffffff;
  --color-slider-track: #e0e0e0;
  --color-slider-thumb: var(--color-primary);
  --color-shadow: rgba(0, 0, 0, 0.1);
}

@layer writing-modes {
  .direction-wrapper {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  .horizontal-tb-wrapper {
    display: flex;
    flex-direction: column;
    align-items: center;
    writing-mode: horizontal-tb;
  }

  input.horizontal-tb {
    width: 9.375rem;
    height: 0.375rem;
  }

  input:not(.horizontal-tb) {
    width: 0.375rem;
    height: 9.375rem;
  }

  .vertical-lr-wrapper {
    display: flex;
    flex-direction: column;
    align-items: center;
    writing-mode: vertical-lr;
  }

  .vertical-rl-wrapper {
    writing-mode: vertical-rl;
  }

  .sideways-lr-wrapper {
    writing-mode: sideways-lr;
  }

  .sideways-rl-wrapper {
    writing-mode: sideways-rl;
  }
}

@layer presentation {
  body {
    font-family: "Inter", sans-serif;
    background-color: var(--color-background);
    color: var(--color-text);
    max-width: 1000px;
    margin: 0 auto;
    padding: 2.5rem 1.25rem;
    line-height: 1.6;
  }

  h1 {
    text-align: center;
    margin-bottom: 0.625rem;
    color: var(--color-text);
    font-size: 2rem;
  }

  .intro {
    text-align: center;
    margin-bottom: 1.875rem;
    color: var(--color-text-light);
    max-width: 700px;
    margin-left: auto;
    margin-right: auto;
    font-size: 1rem;
  }

  .demo-container {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1.5625rem;
    justify-content: center;
  }

  .range-container {
    background-color: var(--color-card);
    padding: 1.5625rem;
    border-radius: 0.5rem;
    box-shadow: 0 2px 8px var(--color-shadow);
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    height: auto;
    min-height: 16.25rem;
  }

  .range-container h3 {
    margin-top: 0;
    margin-bottom: 1.25rem;
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--color-text);
  }

  .range-container p {
    font-size: 0.875rem;
    color: var(--color-text-light);
    margin-top: 0.9375rem;
    text-align: center;
    line-height: 1.4;
  }

  .input-wrapper {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 9.375rem;
    width: 9.375rem;
    position: relative;
  }

  input[type="range"] {
    -webkit-appearance: none;
    background: var(--color-slider-track);
    border-radius: 3px;
    margin: 0;
  }

  input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 1.125rem;
    height: 1.125rem;
    background: var(--color-slider-thumb);
    border-radius: 50%;
    cursor: pointer;
  }

  input[type="range"]::-moz-range-thumb {
    width: 1.125rem;
    height: 1.125rem;
    background: var(--color-slider-thumb);
    border-radius: 50%;
    cursor: pointer;
    border: none;
  }

  input[type="range"]:focus {
    outline: none;
  }

  input[type="range"]:focus::-webkit-slider-thumb {
    background: var(--color-primary-dark);
  }

  .value-display {
    color: var(--color-primary);
    font-weight: 600;
    font-size: 0.875rem;
    margin: 0.625rem;
  }

  .browser-support {
    font-size: 0.75rem;
    color: var(--color-warning);
    margin-top: 0.3125rem;
  }
}
document.querySelectorAll('input[type="range"]').forEach((input) => {
  const wrapper = input.closest('div[class$="-wrapper"]');
  const valueDisplay = wrapper.querySelector(".value-display");

  valueDisplay.textContent = `Value: ${input.value}`;

  input.addEventListener("input", () => {
    valueDisplay.textContent = `Value: ${input.value}`;
  });
});
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.