diff --git a/demo/DemoApp.tsx b/demo/DemoApp.tsx
index f340785..53842a5 100644
--- a/demo/DemoApp.tsx
+++ b/demo/DemoApp.tsx
@@ -56,6 +56,7 @@ export function DemoApp()
const [datetime, setDatetime] = useState(null);
const [selected, setSelected] = useState(null);
+ const [anotherSelected, setAnotherSelected] = useState(null);
const [page, setPage] = useState(11);
@@ -176,6 +177,18 @@ export function DemoApp()
}} value={selected} onChange={setSelected} selectibleMaxCount={3} placeholder={"Simple test"}>
Simple select test
+
+
+
+
+
+
HTML
diff --git a/index.ts b/index.ts
index 681f0ec..3ed05de 100644
--- a/index.ts
+++ b/index.ts
@@ -15,6 +15,7 @@ export * from "./src/Components/Dates/Datepicker";
export * from "./src/Components/Floating/Float";
export * from "./src/Components/Floating/Tooltip";
export * from "./src/Components/Forms/Checkbox";
+export * from "./src/Components/Forms/CustomValidationRule";
export * from "./src/Components/Forms/DatepickerInput";
export * from "./src/Components/Forms/PasswordInput";
export * from "./src/Components/Forms/Radio";
diff --git a/package.json b/package.json
index 0951e39..d935e29 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "version": "1.4.2",
+ "version": "1.5.0",
"name": "@kernelui/core",
"description": "Kernel UI Core.",
"scripts": {
diff --git a/src/Components/Forms/CustomValidationRule.tsx b/src/Components/Forms/CustomValidationRule.tsx
new file mode 100644
index 0000000..47b6b38
--- /dev/null
+++ b/src/Components/Forms/CustomValidationRule.tsx
@@ -0,0 +1,24 @@
+import React, {useEffect, useRef} from "react";
+
+/**
+ * Custom validation rule in a form.
+ */
+export function CustomValidationRule({valid, errorMessage}: {
+ valid: boolean;
+ errorMessage: string;
+})
+{
+ // HTML virtual input ref.
+ const ref = useRef();
+
+ // When the validation is invalid, set a custom error message, set the custom error message.
+ useEffect(() => {
+ ref.current.setCustomValidity(valid ? "" : errorMessage);
+ }, [ref, valid, errorMessage]);
+
+ return (
+ {}} />
+ );
+}
diff --git a/src/Components/Select/Select.tsx b/src/Components/Select/Select.tsx
index 20a2e66..b23b738 100644
--- a/src/Components/Select/Select.tsx
+++ b/src/Components/Select/Select.tsx
@@ -3,6 +3,7 @@ import {Suggestible} from "./Suggestible";
import {OptionsSuggestions, useSuggestionsNavigation} from "./OptionsSuggestions";
import {classes, Modify, normalizeString} from "../../Utils";
import {CaretDown, Check, X} from "@phosphor-icons/react";
+import {CustomValidationRule} from "../Forms/CustomValidationRule";
/**
* Generic select component properties.
@@ -37,6 +38,12 @@ export type SelectProperties = React.PropsW
*/
match?: (search: string, option: Option) => boolean;
+ /**
+ * Min count of options to allow to select.
+ * 0 by default, 1 when required is true.
+ */
+ selectibleMinCount?: number;
+
/**
* Max count of options to allow to select.
* 1 by default when multiple is false, infinity when multiple is true.
@@ -74,6 +81,7 @@ export function Select(
className,
value, onChange,
options, renderOption, match,
+ required, selectibleMinCount,
selectibleMaxCount, multiple,
blurOnSelect, blurWhenMaxCountSelected,
// Properties to pass down.
@@ -90,6 +98,10 @@ export function Select(
// If `multiple` is set and `selectibleMaxCount` is not, allow an infinite count of options to select.
selectibleMaxCount = selectibleMaxCount ?? ((multiple === undefined ? false : multiple) ? Infinity : 1);
+ // By default, allow to select no option.
+ // If `required` is set, `selectibleMinCount` will be set as 1 by default.
+ selectibleMinCount = selectibleMinCount ?? (required ? 1 : 0);
+
// true by default.
blurOnSelect = blurOnSelect === undefined ? false : blurOnSelect;
blurWhenMaxCountSelected = blurWhenMaxCountSelected === undefined ? true : blurWhenMaxCountSelected;
@@ -213,6 +225,9 @@ export function Select(
+ = selectibleMinCount}
+ errorMessage={`At least ${selectibleMinCount} option${selectibleMinCount > 1 ? "s are" : " is"} required.`} />
+
{ // Showing each selected value.
selectedOptions.map(([optionKey, option]) => (
diff --git a/src/styles/_common.less b/src/styles/_common.less
index df3448c..6db24ac 100644
--- a/src/styles/_common.less
+++ b/src/styles/_common.less
@@ -27,3 +27,9 @@ p
margin: 0.75em auto;
line-height: 1.6em;
}
+
+.virtual
+{
+ position: absolute;
+ opacity: 0;
+}