150 €750 €
React + MotionEingabefelder

Preisbereich-Slider

Zwei Regler für Mindest- und Höchstpreis, darüber ein kleines Histogramm, das zeigt, wo sich die Preise ballen.

Einstellungen

150€
750€
1

Code

import { useState } from "react";
import { motion } from "framer-motion";

const spring = { type: "spring" as const, stiffness: 300, damping: 30 };

const bars = [5, 8, 13, 20, 28, 35, 42, 50, 46, 38, 31, 23, 16, 10];

const rangeClass = [
  "h-1 w-full appearance-none rounded-full bg-black/5 outline-none dark:bg-white/10",
  "[&::-webkit-slider-thumb]:h-[22px] [&::-webkit-slider-thumb]:w-[22px] [&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:shadow-[0_1px_4px_rgba(0,0,0,0.25),0_0_0_0.5px_rgba(0,0,0,0.06)]",
  "[&::-moz-range-thumb]:h-[22px] [&::-moz-range-thumb]:w-[22px] [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:border-none [&::-moz-range-thumb]:bg-white [&::-moz-range-thumb]:shadow-[0_1px_4px_rgba(0,0,0,0.25)]",
].join(" ");

interface PriceRangeProps {
  value?: [number, number];
  defaultValue?: [number, number];
  onChange?: (value: [number, number]) => void;
  height?: number;
}

export default function PriceRange({
  value,
  defaultValue = [150, 750],
  onChange,
  height = 1,
}: PriceRangeProps) {
  const [internal, setInternal] = useState<[number, number]>(defaultValue);
  const [a, b] = value ?? internal;

  const set = (next: [number, number]) => {
    if (value === undefined) setInternal(next);
    onChange?.(next);
  };

  return (
    <div className="w-72 rounded-[22px] bg-white p-5 text-[#1d1d1f] shadow-[0_1px_2px_rgba(0,0,0,0.03),0_8px_28px_rgba(0,0,0,0.05)] dark:bg-[#1c1c1e] dark:text-[#f5f5f7]">
      <div className="mb-3 flex h-16 items-end gap-1">
        {bars.map((h, i) => (
          <motion.i
            key={i}
            className="flex-1 rounded-t bg-[#0071e3]/30"
            animate={{ height: h * height }}
            transition={{ ...spring, delay: i * 0.02 }}
          />
        ))}
      </div>
      <div className="space-y-2">
        <input
          aria-label="Mindestpreis"
          className={rangeClass}
          type="range"
          min="0"
          max="1000"
          value={a}
          onChange={(e) => set([Math.min(Number(e.target.value), b - 25), b])}
        />
        <input
          aria-label="Höchstpreis"
          className={rangeClass}
          type="range"
          min="0"
          max="1000"
          value={b}
          onChange={(e) => set([a, Math.max(Number(e.target.value), a + 25)])}
        />
      </div>
      <div className="mt-3 flex justify-between text-sm">
        <span>{a} €</span>
        <span>{b} €</span>
      </div>
    </div>
  );
}

Prompt für KI

Füg ihn in ChatGPT, Claude oder Cursor ein und der Baustein wird mit diesen Einstellungen an dein Projekt angepasst, auch ohne React.

Mehr aus Eingabefelder

Wofür du ihn nutzen kannst

Ein Preisfilter mit Histogramm zeigt Käufern, wo die meisten Produkte liegen, bevor sie überhaupt etwas ziehen. Man kennt das von Ferienwohnungsportalen, Gebrauchtwagenbörsen und größeren Onlineshops. Die beiden Regler kreuzen sich nie, und die Preise darunter aktualisieren sich beim Ziehen. Hat dein Katalog eine Filterleiste, passt dieser Preisbereich-Slider genau dort hinein.

Die Balken in der Demo sind Beispieldaten. Füttere sie mit deiner echten Preisverteilung, sonst führen sie in die Irre. Pass die Höhe des Histogramms an deine Seitenleiste an und änder das Währungszeichen, falls du nicht in Euro verkaufst.