diff --git a/docs/docs/components/range_facet.md b/docs/docs/components/range_facet.md
new file mode 100644
index 00000000..001916b8
--- /dev/null
+++ b/docs/docs/components/range_facet.md
@@ -0,0 +1,382 @@
+---
+id: range-facet
+title: RangeFacet
+---
+
+`RangeFacet` renders a histogram, slider, and optional default/custom ranges for a numeric year range.
+
+It reads buckets from the `results` aggregations and stores the selected range in the query `filters`.
+
+## Usage
+
+```jsx
+
+```
+
+## Aggregation format
+
+The component expects the aggregation result under `results.aggregations[aggName].buckets`
+with a numeric `key` (or `key_as_string`) and `doc_count`:
+
+```json
+{
+ "years": {
+ "buckets": [
+ { "key": 2021, "doc_count": 12 },
+ { "key": 2022, "doc_count": 7 }
+ ]
+ }
+}
+```
+
+## Filters format
+
+The selected filter is stored as `[ "", "" ]`.
+`` and `` can be `YYYY` or full ISO dates (`YYYY-MM-DD`) when custom ranges
+include months/days.
+
+## Props
+
+* **title** `String`
+
+ The title rendered in the card header.
+
+* **agg** `Object`
+
+ An object that describes the aggregation to read from `results`:
+
+ * **aggName** `String`: the aggregation name to look for in `results`
+
+* **rangeSeparator** `String`
+
+ The separator used when building the filter value (for example `..` or `--`).
+
+* **defaultRanges** `Array` *optional*
+
+ Default ranges rendered as checkboxes. Each entry should have:
+
+ * **label** `String`
+ * **type** `String`: `"years"` or `"months"`
+ * **value** `Number`: number of years/months back
+
+* **enableCustomRange** `Boolean` *optional*
+
+ When `true`, enables the custom date range checkbox with optional month/day inputs.
+
+* **customDatesLabel** `String` *optional*
+
+ Label for the button that expands the custom date inputs (year/month/day). Default: `"Custom Dates"`.
+
+* **dateRangeToLabel** `String` *optional*
+
+ Text shown between the "from" and "to" date inputs. Default: `"to"`.
+
+* **datePlaceholders** `Object` *optional*
+
+ Placeholder text for the date input fields. Only keys you provide are used; others keep their defaults. Keys: `YYYY`, `MM`, `DD`. Example: `{ YYYY: "Year", MM: "Mo", DD: "Day" }`. Default placeholders when not set: `"YYYY"`, `"MM"`, `"DD"`.
+
+* **histogramHeight** `Number` *optional*
+
+ Height in pixels for the histogram area.
+
+* **overridableId** `String` *optional*
+
+ Optional string to define a specific overridable id.
+
+## Usage when overriding
+
+### Overriding full component
+
+Use this when you want to replace the whole `RangeFacet` logic and UI.
+
+Brief flow (matches the default behavior):
+
+1. Read buckets from `currentResultsState.data.aggregations[agg.aggName].buckets`.
+2. Compute `min/max` years from bucket keys.
+3. Compute the histogram data with aggregation keys and doc counts.
+4. Store the selected range in `currentQueryState.filters` as:
+ `[agg.aggName, `${from}${rangeSeparator}${to}`]`.
+5. Render your own UI (histogram/slider/etc).
+
+Example with only histogram and custom filter facet:
+
+```jsx
+class MyRangeFacet extends React.Component {
+ constructor(props) {
+ super(props);
+ const { min, max } = this.getMinMax();
+ this.state = { range: [min, max], activeFilter: null };
+ }
+
+ applyRange = (from, to) => {
+ // Apply the filter
+ };
+
+ onBarClick = (year) => {
+ this.applyRange(year, year);
+ };
+
+ onClear = () => {
+ // Clear the filter
+ };
+
+ getBuckets = () => {
+ const { currentResultsState, agg } = this.props;
+ const resultsAggregations = currentResultsState?.data?.aggregations;
+ return resultsAggregations?.[agg.aggName]?.buckets ?? [];
+ };
+
+ render() {
+ const { title, agg, rangeSeparator, currentQueryState, histogramHeight } =
+ this.props;
+ const { min, max } = this.getMinMax();
+ const hasActiveFilter;
+ // Extract the buckets in aggregations
+ const buckets = getBuckets();
+ // Active filter range: [from(year), to(year)]
+ const { range } = this.state
+
+ const containerCmp = (
+ <>
+
+ this.applyRange(r[0], r[1])}
+ onClear={this.onClear}
+ />
+ >
+ );
+
+ return (
+
+ );
+ }
+}
+
+const overriddenComponents = {
+ RangeFacet: MyRangeFacet,
+};
+```
+
+### Overriding the element
+
+Wraps the default content and lets you customize the header or layout while keeping
+the built-in histogram/slider/custom filters.
+
+```jsx
+const MyRangeFacetElement = ({ title, containerCmp, hasActiveFilter, onClear }) => {
+ return (
+
+
+ {title}
+ {hasActiveFilter && (
+
+ )}
+
+ {containerCmp}
+
+ );
+};
+
+const overriddenComponents = {
+ "RangeFacet.element": MyRangeFacetElement,
+};
+```
+
+### Overriding the histogram
+
+Replace the histogram visualization. Use `data` and `range` to show counts and
+highlight the selected years. Call `onBarClick(year)` to update the range.
+
+```jsx
+const MyRangeHistogram = ({ data, range, onBarClick }) => {
+ return (
+
+ {data.map((item) => {
+ ...
+ })}
+
+ );
+};
+
+const overriddenComponents = {
+ "RangeFacet.Histogram.element": MyRangeHistogram,
+};
+```
+
+#### Tooltip override (histogram)
+
+The histogram tooltip is its own overridable element. The `tooltip` value has the
+shape `{ year, count, x, y }` where `x/y` are viewport coordinates used to position
+the tooltip.
+
+```jsx
+const MyHistogramTooltip = ({ tooltip }) => {
+ if (!tooltip) return null;
+ return (
+
+ {tooltip.year}: {tooltip.count}
+
+ );
+};
+
+const overriddenComponents = {
+ "RangeFacet.Histogram.Tooltip.element": MyHistogramTooltip,
+};
+```
+
+### Overriding the slider
+
+Replace the range slider. Call `onChange([min, max])` when the selected range changes.
+
+```jsx
+const MyRangeSlider = ({ min, max, value, onChange }) => {
+ ...
+};
+
+const overriddenComponents = {
+ "RangeFacet.Slider.element": MyRangeSlider,
+};
+```
+
+### Overriding the default filters
+
+Replace the default ranges list. Call `onToggle(range, checked)` to select or clear
+a range option.
+
+```jsx
+const MyDefaultFilters = ({ ranges, activeLabel, onToggle }) => {
+ ...
+};
+
+const overriddenComponents = {
+ "RangeFacet.DefaultFilters.element": MyDefaultFilters,
+};
+```
+
+### Overriding the custom filter
+
+Replace the custom range checkbox and inputs wrapper. Use `checked/expanded` to
+control layout and render `dateError` when validation fails.
+
+```jsx
+const MyCustomFilter = ({ checked, expanded, dateError, activeFilter, children }) => {
+ ...
+};
+
+const overriddenComponents = {
+ "RangeFacet.CustomFilter.element": MyCustomFilter,
+};
+```
+
+### Overriding the date range inputs (for custom filter)
+
+Replace the date input layout for the custom filter. Use `format` to decide which
+parts to render and `values` to populate them.
+
+```jsx
+const MyDateRangeInputs = ({ format, values, disabled, children }) => {
+ ...
+};
+
+const overriddenComponents = {
+ "RangeFacet.DateInputs.Layout": MyDateRangeInputs,
+};
+```
+
+`format` controls the input structure:
+
+- `YYYY` renders a single row with year-only inputs.
+- `YYYY-MM` and `YYYY-MM-DD` render stacked rows for from/to values.
+
+### RangeFacet parameters
+
+Component that wraps the histogram, slider, and optional filters.
+
+* **title** `String`
+
+ The title to render.
+
+* **containerCmp** `React component`
+
+ The rendered content (histogram, slider, and filters).
+
+* **hasActiveFilter** `Boolean`
+
+ `true` if a range filter is active, `false` otherwise.
+
+* **onClear** `Function`
+
+ Function to call to clear the active range filter.
+
+## Callback methods used by overrides
+
+* **onClear** `Function`
+
+ Clears the active range filter and resets to the full available range.
+
+* **onBarClick** `Function`
+
+ Accepts a `year` and updates the range to that single year.
+
+* **onChange** `Function`
+
+ Accepts `[from, to]` to update the selected range (used by slider overrides).
+
+* **onToggle** `Function`
+
+ Accepts `(range, checked)` to select a default range or clear it.
+
+## Utilities
+
+Helpers from `src/lib/components/RangeFacet/utils.js` used by `RangeFacet` and its sub-components.
+
+* **extractBuckets(resultsAggregations, aggName)**: read aggregation buckets safely.
+* **getKey(bucket)**: returns `key_as_string` when present, otherwise `key`.
+* **getHistogramData(buckets, min, max)**: build continuous year data with counts.
+* **resolveDefaultRange(range, min, max, rangeSeparator)**: compute the year range
+ and optional ISO date range for a default option.
+* **normalizeFilterValue(filterValue, rangeSeparator, minYear, maxYear)**: sanitize
+ and normalize a filter string like `YYYY..YYYY` or ISO dates.
+* **parseFilterYears(filterValue, rangeSeparator)**: parse years from a filter
+ string (supports ISO dates).
+* **findDefaultLabel(defaultRanges, filterValue, min, max, rangeSeparator)**:
+ match an active filter to a default range label.
+* **buildDateRange({ fromYear, fromMonth, fromDay, toYear, toMonth, toDay, rangeSeparator })**:
+ build a `YYYY..YYYY` or ISO `YYYY-MM-DD..YYYY-MM-DD` string.
+* **RANGE_MODES**: enum with `DEFAULT` and `CUSTOM` used for optional default and custom filters.
diff --git a/docs/website/sidebars.json b/docs/website/sidebars.json
index 77cd9ec6..07e5fb69 100644
--- a/docs/website/sidebars.json
+++ b/docs/website/sidebars.json
@@ -12,6 +12,7 @@
"components/react-searchkit",
"components/active-filters",
"components/bucket-aggregation",
+ "components/range-facet",
"components/count",
"components/empty-results",
"components/error",