diff --git a/R/export.R b/R/export.R
index ca5eae4a99..33f6d0a375 100644
--- a/R/export.R
+++ b/R/export.R
@@ -725,15 +725,19 @@ as_latex <- function(data) {
     latex_packages <- NULL
   }
 
+  table_width_bookends <- derive_table_width_bookends(data = data)
+
   # Compose the LaTeX table
   knitr::asis_output(
     paste0(
+      table_width_bookends[1L],
       table_start,
       heading_component,
       columns_component,
       body_component,
       table_end,
       footer_component,
+      table_width_bookends[2L],
       collapse = ""
     ),
     meta = latex_packages
diff --git a/R/utils_render_latex.R b/R/utils_render_latex.R
index 0ae6ed157d..d4120d4e85 100644
--- a/R/utils_render_latex.R
+++ b/R/utils_render_latex.R
@@ -183,6 +183,45 @@ create_table_start_l <- function(data) {
             ">{\\raggedright\\arraybackslash}"
           )
 
+        # Check if column width was set using gt::pct and
+        # convert to Latex friendly terminology (i.e.,
+        # '14.7%' becomes '0.147\\linewidth')
+        if (grepl('^[[:digit:].]+%$', col_widths[i])) {
+
+          table_width <- dt_options_get_value(data = data, option = 'table_width')
+
+          col_pct <- as.numeric(gsub('%$', '', col_widths[i])) / 100
+
+          if (table_width == 'auto') {
+
+            # Table width not specified, use all available space
+            col_scalar <- col_pct
+            tab_unit <- '\\linewidth'
+
+          } else if (endsWith(table_width, suffix = '%')) {
+
+            # If table width is expressed as a percentage, adjust the scaler
+            col_scalar <- col_pct * as.numeric(gsub('%', '', table_width)) / 100
+            tab_unit <- '\\linewidth'
+
+          } else {
+
+            # When table width is expressed in units, convert to points
+            col_scalar <- col_pct * convert_to_px(table_width) * 0.75 # 0.75 converts pixels to points
+            tab_unit <- 'pt'
+
+          }
+
+          col_widths[i] <-
+            paste0(
+              "\\dimexpr ",
+              col_scalar,
+              tab_unit,
+              "-2\\tabcolsep-1.5\\arrayrulewidth"
+            )
+
+        }
+
         col_defs_i <- paste0(align, "p{", col_widths[i], "}")
 
       } else {
@@ -205,11 +244,18 @@ create_table_start_l <- function(data) {
       paste0(col_defs[seq_along(stub_layout)], "|")
   }
 
+  # If a table width is specified, add an extra column
+  # space to fill in enough space to match the width
+  extra_sep <- ''
+  if (dt_options_get_value(data = data, option = 'table_width') != 'auto')
+    extra_sep <- '@{\\extracolsep{\\fill}}'
+
   # Generate setup statements for table including default left
   # alignments and vertical lines for any stub columns
   paste0(
     longtable_post_length,
     "\\begin{longtable}{",
+    extra_sep,
     paste(col_defs, collapse = ""),
     "}\n",
     collapse = ""
@@ -1103,3 +1149,70 @@ split_row_content <- function(x) {
 
   split(row_content, ceiling(seq_along(row_content) / ncol(x)))
 }
+
+derive_table_width_bookends <- function(data) {
+
+  table_width <- dt_options_get_value(data = data, 'table_width')
+
+  # Bookends are not required if a table width is not specified
+  if (table_width == 'auto') {
+
+    bookends <- c('', '')
+
+  } else if (endsWith(table_width, "%")) {
+
+    tw <- as.numeric(gsub('%', '', table_width))
+
+    side_width <-
+      ((100 - tw) / 200) %>%
+      format(scientific = FALSE, trim = TRUE)
+
+    bookends <-
+      c(
+        paste0(
+          "\\newlength\\holdLTleft",
+          "\\newlength\\holdLTright",
+          "\\setlength\\holdLTleft{\\LTleft}\\relax",
+          "\\setlength\\holdLTright{\\LTright}\\relax",
+          sprintf(
+            '\\setlength\\LTleft{%s\\linewidth}\n\\setlength\\LTright{%s\\linewidth}',
+            side_width,
+            side_width
+          ),
+          collapse = "\n"
+        ),
+        "\\setlength\\LTleft{\\holdLTleft}\n\\setlength\\LTright{\\holdLTright}"
+      )
+
+  } else {
+
+    width_in_pt <- 0.75 * convert_to_px(table_width)
+
+    halfwidth_in_pt <- format(width_in_pt / 2, scientific = FALSE, trim = TRUE)
+
+    bookends <-
+      c(
+        paste0(
+          "\\newlength\\holdLTleft",
+          "\\newlength\\holdLTright",
+          "\\setlength\\holdLTleft{\\LTleft}\\relax",
+          "\\setlength\\holdLTright{\\LTright}\\relax",
+          sprintf(
+            "\\setlength\\LTleft{\\dimexpr(0.5\\linewidth - %spt)}\n\\setlength\\LTright{\\dimexpr(0.5\\linewidth - %spt)}",
+            halfwidth_in_pt,
+            halfwidth_in_pt
+          ),
+          collapse = '\n'
+        ),
+        paste0(
+          "\\setlength\\LTleft{\\holdLTleft}",
+          "\\setlength\\LTright{\\holdLTright}",
+          collapse = "\n"
+        )
+      )
+
+  }
+
+  bookends
+
+}
diff --git a/tests/testthat/test-as_latex.R b/tests/testthat/test-as_latex.R
new file mode 100644
index 0000000000..17e74a2380
--- /dev/null
+++ b/tests/testthat/test-as_latex.R
@@ -0,0 +1,50 @@
+test_that("Table width correctly output in LaTeX", {
+
+  gt_latex_width_1 <-
+    gt(exibble) %>%
+    tab_options(table.width = pct(90)) %>%
+    as_latex()
+
+  start_pt <- regexpr("begin\\{longtable", gt_latex_width_1)
+
+  expect_gt(start_pt, 0)  # Verifies the long table command appears in the text
+
+  end_pt <- regexpr("end\\{longtable", gt_latex_width_1)
+
+  expect_gt(end_pt, 0)
+
+  # Verify that the holdLTleft and holdLTright variables are defined and set
+  latex_prefix <- substr(gt_latex_width_1, 1L, start_pt)
+
+  expect_match(latex_prefix, "\\\\newlength\\\\holdLTleft")
+
+  expect_match(latex_prefix, "\\\\newlength\\\\holdLTright")
+
+  expect_match(latex_prefix, "\\\\setlength\\\\holdLTleft\\{\\\\LTleft\\}\\\\relax")
+
+  expect_match(latex_prefix, "\\\\setlength\\\\holdLTright\\{\\\\LTright\\}\\\\relax")
+
+  # Verify that LTleft and LTright are correctly specified
+  expect_match(latex_prefix, "\\\\setlength\\\\LTleft\\{0.05\\\\linewidth\\}")
+
+  expect_match(latex_prefix, "\\\\setlength\\\\LTright\\{0.05\\\\linewidth\\}")
+
+  # Verify that after the longtable environment, the LTleft and LT right are
+  # changed back to their previous values
+  latex_suffix <- substr(gt_latex_width_1, end_pt, nchar(gt_latex_width_1))
+
+  expect_match(latex_suffix, "\\\\setlength\\\\LTleft\\{\\\\holdLTleft\\}")
+
+  expect_match(latex_suffix, "\\\\setlength\\\\LTright\\{\\\\holdLTright\\}")
+
+  # Test specification of a table width in pixels
+  gt_latex_width_2 <-
+    gt(exibble) %>%
+    tab_options(table.width = '600px') %>%
+    as_latex()
+
+  expect_match(gt_latex_width_2, "\\\\setlength\\\\LTleft\\{\\\\dimexpr\\(0.5\\\\linewidth - 225pt\\)\\}")
+
+  expect_match(gt_latex_width_2, "\\\\setlength\\\\LTright\\{\\\\dimexpr\\(0.5\\\\linewidth - 225pt\\)\\}")
+
+})
diff --git a/tests/testthat/test-cols_width.R b/tests/testthat/test-cols_width.R
index f96bb06276..43e830f156 100644
--- a/tests/testthat/test-cols_width.R
+++ b/tests/testthat/test-cols_width.R
@@ -897,3 +897,113 @@ test_that("The function `cols_width()` works correctly with a complex table", {
     ) %>%
     expect_true()
 })
+
+test_that("The function `cols_width()` correctly specifies LaTeX table when column widths are specified by user as percentages", {
+
+  # Check that specific suggested packages are available
+  check_suggests()
+
+  # Create a `tbl_latex` object with `gt()` and size
+  # all columns in percentages
+  tbl_latex <-
+    gt(tbl) %>%
+    cols_width(
+      col_1 ~ pct(50),
+      col_2 ~ pct(30),
+      col_3 ~ pct(20),
+      col_4 ~ pct(10)
+    )
+
+  pct_string <- function(x, unit = '\\\\linewidth') {
+
+    prefix <- '>\\{\\\\(raggedright|raggedleft|centering)\\\\arraybackslash\\}'
+
+    sprintf(
+      '%sp\\{\\\\dimexpr %s%s-2\\\\tabcolsep-1.5\\\\arrayrulewidth\\}',
+      prefix,
+      format(x, scientific = FALSE, trim = TRUE),
+      unit
+    )
+
+  }
+
+  build_longtable_regex <- function(...) {
+
+    paste0(
+      c(
+        "\\\\begin\\{longtable\\}\\{",
+        "(@\\{\\\\extracolsep\\{\\\\fill\\}\\})*",
+        c(...),
+        "\\}\\n"
+      ),
+      collapse = ''
+    )
+
+  }
+
+  latex_col_regex <-
+    paste0(
+      c(
+        "\\\\begin\\{longtable\\}\\{",
+        "(@\\{\\\\extracolsep\\{\\\\fill\\}\\})*",
+        # '>\\{\\\\ragged[[:alpha:]]+\\\\arraybackslash'
+       sprintf(">\\{\\\\(raggedright|raggedleft|centering)\\\\arraybackslash\\}p\\{\\\\dimexpr 0\\.%d\\\\linewidth-2\\\\tabcolsep-1.5\\\\arrayrulewidth}",
+               c(5L, 3L, 2L, 1L)),
+        "\\}\\n"
+      ),
+      collapse = ''
+    )
+
+  # Expect that all column widths are expressed as percentage of \linewidth
+  c(0.5, 0.3, 0.2, 0.1) %>%
+    pct_string() %>%
+    build_longtable_regex() %>%
+    grepl(as_latex(tbl_latex)) %>%
+    expect_true()
+
+
+  # Check that LaTeX is correctly generated when only some
+  # column widths are specified as percentages
+  tbl_latex_partial <-
+    gt(tbl) %>%
+    cols_width(
+      col_1 ~ pct(30),
+      col_3 ~ pct(20)
+    )
+
+  c(
+    pct_string(0.3),
+    'r',
+    pct_string(0.2),
+    'r'
+  ) %>%
+    build_longtable_regex() %>%
+    grepl(as_latex(tbl_latex_partial)) %>%
+    expect_true()
+
+  # Check that LaTeX longtable command is correctly generated
+  # when table_width is specified by the user as a percentage
+  tbl_latex_tw_pct <-
+    tbl_latex %>%
+    tab_options(table.width = pct(70))
+
+  (0.7 * c(0.5, 0.3, 0.2, 0.1)) %>%
+    pct_string() %>%
+    build_longtable_regex() %>%
+    grepl(as_latex(tbl_latex_tw_pct)) %>%
+    expect_true()
+
+  # Check that LaTeX longtable command is correctly generated
+  # when table width is specified by user in pixels
+  tbl_latex_tw_px <-
+    tbl_latex %>%
+    tab_options(table.width = '400px')
+
+  (400 * 0.75 * c(0.5, 0.3, 0.2, 0.1)) %>%
+    pct_string(unit = 'pt') %>%
+    build_longtable_regex() %>%
+    grepl(as_latex(tbl_latex_tw_px))
+
+
+})
+