diff --git a/doc/source/whatsnew/v1.5.0.rst b/doc/source/whatsnew/v1.5.0.rst
index 8acf0ab3b7761..902279f44299e 100644
--- a/doc/source/whatsnew/v1.5.0.rst
+++ b/doc/source/whatsnew/v1.5.0.rst
@@ -566,6 +566,8 @@ I/O
- Bug in Parquet roundtrip for Interval dtype with ``datetime64[ns]`` subtype (:issue:`45881`)
- Bug in :func:`read_excel` when reading a ``.ods`` file with newlines between xml elements (:issue:`45598`)
- Bug in :func:`read_parquet` when ``engine="fastparquet"`` where the file was not closed on error (:issue:`46555`)
+- :meth:`to_html` now excludes the ``border`` attribute from ``
`` elements when ``border`` keyword is set to ``False``.
+-
Period
^^^^^^
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
index 1a28d9f44ae28..bcbd6437d6333 100644
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -2892,7 +2892,7 @@ def to_html(
classes: str | list | tuple | None = None,
escape: bool = True,
notebook: bool = False,
- border: int | None = None,
+ border: int | bool | None = None,
table_id: str | None = None,
render_links: bool = False,
encoding: str | None = None,
diff --git a/pandas/io/formats/format.py b/pandas/io/formats/format.py
index ea938c924ae0c..fd79d418658ea 100644
--- a/pandas/io/formats/format.py
+++ b/pandas/io/formats/format.py
@@ -1058,7 +1058,7 @@ def to_html(
encoding: str | None = None,
classes: str | list | tuple | None = None,
notebook: bool = False,
- border: int | None = None,
+ border: int | bool | None = None,
table_id: str | None = None,
render_links: bool = False,
) -> str | None:
diff --git a/pandas/io/formats/html.py b/pandas/io/formats/html.py
index 0c927277e899a..dfd95b96c68e8 100644
--- a/pandas/io/formats/html.py
+++ b/pandas/io/formats/html.py
@@ -44,7 +44,7 @@ def __init__(
self,
formatter: DataFrameFormatter,
classes: str | list[str] | tuple[str, ...] | None = None,
- border: int | None = None,
+ border: int | bool | None = None,
table_id: str | None = None,
render_links: bool = False,
) -> None:
@@ -57,8 +57,11 @@ def __init__(
self.bold_rows = self.fmt.bold_rows
self.escape = self.fmt.escape
self.show_dimensions = self.fmt.show_dimensions
- if border is None:
+ if border is None or border is True:
border = cast(int, get_option("display.html.border"))
+ elif not border:
+ border = None
+
self.border = border
self.table_id = table_id
self.render_links = render_links
@@ -237,8 +240,13 @@ def _write_table(self, indent: int = 0) -> None:
else:
id_section = f' id="{self.table_id}"'
+ if self.border is None:
+ border_attr = ""
+ else:
+ border_attr = f' border="{self.border}"'
+
self.write(
- f'',
+ f'',
indent,
)
diff --git a/pandas/tests/io/formats/test_to_html.py b/pandas/tests/io/formats/test_to_html.py
index aa8508d8e8942..3059efef09095 100644
--- a/pandas/tests/io/formats/test_to_html.py
+++ b/pandas/tests/io/formats/test_to_html.py
@@ -342,9 +342,9 @@ def test_to_html_truncate_multi_index(sparsify, expected, datapath):
"option,result,expected",
[
(None, lambda df: df.to_html(), "1"),
- (None, lambda df: df.to_html(border=0), "0"),
- (0, lambda df: df.to_html(), "0"),
- (0, lambda df: df._repr_html_(), "0"),
+ (None, lambda df: df.to_html(border=2), "2"),
+ (2, lambda df: df.to_html(), "2"),
+ (2, lambda df: df._repr_html_(), "2"),
],
)
def test_to_html_border(option, result, expected):
diff --git a/pandas/tests/io/test_html.py b/pandas/tests/io/test_html.py
index 99fa31726445a..ea50464155ad5 100644
--- a/pandas/tests/io/test_html.py
+++ b/pandas/tests/io/test_html.py
@@ -1148,6 +1148,25 @@ def test_to_html_timestamp(self):
result = df.to_html()
assert "2000-01-01" in result
+ def test_to_html_borderless(self):
+ df = DataFrame([{"A": 1, "B": 2}])
+ out_border_default = df.to_html()
+ out_border_true = df.to_html(border=True)
+ out_border_explicit_default = df.to_html(border=1)
+ out_border_nondefault = df.to_html(border=2)
+ out_border_zero = df.to_html(border=0)
+
+ out_border_false = df.to_html(border=False)
+
+ assert ' border="1"' in out_border_default
+ assert out_border_true == out_border_default
+ assert out_border_default == out_border_explicit_default
+ assert out_border_default != out_border_nondefault
+ assert ' border="2"' in out_border_nondefault
+ assert ' border="0"' not in out_border_zero
+ assert " border" not in out_border_false
+ assert out_border_zero == out_border_false
+
@pytest.mark.parametrize(
"displayed_only,exp0,exp1",
[