diff --git a/src/wtforms/fields/choices.py b/src/wtforms/fields/choices.py
index 66a9719d..0682d30e 100644
--- a/src/wtforms/fields/choices.py
+++ b/src/wtforms/fields/choices.py
@@ -59,6 +59,7 @@ class Choice(NamedTuple):
label: str
selected: bool
render_kw: dict
+ disabled: bool = False
@dataclass
@@ -82,6 +83,7 @@ class SelectChoice:
label: str = None # type: ignore[assignment]
render_kw: dict = field(default_factory=dict)
optgroup: str | None = None
+ disabled: bool = False
def __post_init__(self):
if self.label is None:
@@ -365,6 +367,7 @@ def iter_choices(self):
label=c.label,
selected=self.coerce(c.value) == self.data,
render_kw=c.render_kw,
+ disabled=c.disabled,
)
for c in choices
]
diff --git a/src/wtforms/widgets/core.py b/src/wtforms/widgets/core.py
index 9b95bd0e..fb125825 100644
--- a/src/wtforms/widgets/core.py
+++ b/src/wtforms/widgets/core.py
@@ -448,6 +448,8 @@ def render_option(cls, choice, **kwargs):
options = {"value": value, **(choice.render_kw or {}), **kwargs}
if choice.selected:
options["selected"] = True
+ if choice.disabled:
+ options["disabled"] = True
label = escape(choice.label or choice.value)
return Markup(f"")
diff --git a/tests/fields/test_select.py b/tests/fields/test_select.py
index 7618118c..a5ac0840 100644
--- a/tests/fields/test_select.py
+++ b/tests/fields/test_select.py
@@ -445,8 +445,14 @@ def test_iter_groups_items_unpack_as_3_2_tuples():
)
form = F(a="a")
for _label, items in form.a.iter_groups():
- for value, label, selected, render_kw in items:
- assert (value, label, selected, render_kw) == ("a", "Foo", True, {})
+ for value, label, selected, render_kw, disabled in items:
+ assert (value, label, selected, render_kw, disabled) == (
+ "a",
+ "Foo",
+ True,
+ {},
+ False,
+ )
def test_dict_str_str_flat_choices():
@@ -707,8 +713,11 @@ def test_iter_choices_tuple_unpacking():
a=SelectField(choices=[SelectChoice("a", "Foo"), SelectChoice("b", "Bar")])
)
form = F(a="a")
- unpacked = [(v, lab, sel, rk) for v, lab, sel, rk in form.a.iter_choices()]
- assert unpacked == [("a", "Foo", True, {}), ("b", "Bar", False, {})]
+ unpacked = [
+ (v, lab, sel, rk, disabled)
+ for v, lab, sel, rk, disabled in form.a.iter_choices()
+ ]
+ assert unpacked == [("a", "Foo", True, {}, False), ("b", "Bar", False, {}, False)]
def test_select_field_enum_renders_selected():
@@ -716,3 +725,19 @@ def test_select_field_enum_renders_selected():
F = make_form(a=SelectField(choices=SelectChoice.from_enum(_Plain), coerce=_Plain))
form = F(a=_Plain.GREEN)
assert '' in form.a()
+
+
+def test_disabled_option():
+ """SelectChoice supports disable=True, rendering