Skip to main content

build_html/
html_container.rs

1//! Defines the `HtmlContainer` Trait
2
3use std::iter::empty;
4
5use crate::{Container, Html, HtmlChild, HtmlElement, HtmlTag, Table};
6
7/// An HTML element that can contain other HTML elements
8///
9/// The methods on this trait are implemented generically, allowing any type (or combination of
10/// types) implementing [`ToString`] to be passed in. For example, we can pass an `Ipv4Addr` object
11/// into `with_paragraph` directly:
12///
13/// ```
14/// # use build_html::*;
15/// # use std::net::Ipv4Addr;
16/// let content = HtmlElement::new(HtmlTag::Div)
17///     .with_paragraph(Ipv4Addr::new(127, 0, 0, 1))
18///     .to_html_string();
19/// assert_eq!(content, "<div><p>127.0.0.1</p></div>")
20/// ```
21///
22/// Attributes can be passed in using any type that implements [`IntoIterator`] for 2-tuples of
23/// objects implementing `ToString`. That includes (as of Rust 1.53) arrays of `&str`s, which are
24/// very handy when content is known. For more dynamic attribute action,
25/// [`HashMap`](std::collections::HashMap)s can also be used.
26///
27/// ```
28/// # use build_html::*;
29/// let content = HtmlElement::new(HtmlTag::Div)
30///     .with_paragraph_attr("123", [("id", "paragraph"), ("class", "action")])
31///     .to_html_string();
32/// assert_eq!(content, r#"<div><p id="paragraph" class="action">123</p></div>"#)
33/// ```
34///
35/// There are two different ways of interacting with `HtmlContainer` objects which will suit
36/// different use cases. The first is using the *with* API, which consumes the calling container.
37/// Because the calling container is consumed and returned, it can be chained effectively. This
38/// makes it very useful for building containers whose content is known ahead of time, and for
39/// building content using iterators. For example:
40///
41/// ```
42/// # use build_html::*;
43/// // Aggregating content
44/// let list_items = (0..3)
45///     .map(|x| format!("List item {}", x))
46///     .fold(Container::new(ContainerType::OrderedList), |a, n| a.with_paragraph(n));
47///
48/// // Defining content literally
49/// let content = HtmlElement::new(HtmlTag::Div)
50///     .with_paragraph("paragraph text")
51///     .with_container(list_items)
52///     .to_html_string();
53///
54/// assert_eq!(
55///     content,
56///     concat!(
57///         "<div><p>paragraph text</p><ol>",
58///         "<li><p>List item 0</p></li>",
59///         "<li><p>List item 1</p></li>",
60///         "<li><p>List item 2</p></li></ol></div>"
61///     )
62/// )
63/// ```
64///
65/// The other is using the *add* API, which acts on mutable references. This method is effective for
66/// more imperative programming and more delicate control flow.
67///
68/// ```
69/// # use build_html::*;
70/// let mut container = HtmlElement::new(HtmlTag::Div);
71/// if true {
72///     container.add_paragraph("optional content");
73/// }
74/// for i in 0..3 {
75///     container.add_paragraph(format!("Item: {}", i));
76/// }
77/// assert_eq!(
78///     container.to_html_string(),
79///     concat!(
80///         "<div><p>optional content</p>",
81///         "<p>Item: 0</p><p>Item: 1</p>",
82///         "<p>Item: 2</p></div>"
83///     )
84/// );
85/// ```
86pub trait HtmlContainer: Html + Sized {
87    /// Adds the specified HTML element to this container
88    ///
89    /// This method can be used as an escape hatch to insert arbitrary types into the HTML document,
90    /// helping to make up for those types which are not supported natively by this library. This
91    /// can be done by defining your own types that implement the [`Html`] trait.
92    ///
93    /// If you need a simple one-off, it may be more convenient to insert the element as a raw
94    /// string using [`add_raw`](HtmlContainer::add_raw) method instead
95    ///
96    /// # Example
97    /// ```
98    /// # use build_html::*;
99    /// #[derive(Debug)]
100    /// struct Span {
101    ///     content: String
102    /// }
103    ///
104    /// impl Span {
105    ///     pub fn new(content: impl ToString) -> Self {
106    ///         Span { content: content.to_string() }
107    ///     }
108    /// }
109    ///
110    /// impl Html for Span {
111    ///     fn to_html_string(&self) -> String {
112    ///         format!("<span>{}</span>", self.content)
113    ///     }
114    /// }
115    ///
116    /// let mut content = HtmlElement::new(HtmlTag::Div);
117    /// content.add_html(Span::new("inner"));
118    /// assert_eq!(content.to_html_string(), "<div><span>inner</span></div>");
119    /// ```
120    fn add_html<H: Html>(&mut self, html: H);
121
122    /// Consumes the container, returning it with the specified HTML element added to it
123    ///
124    /// This method can be used as an escape hatch to insert arbitrary types into the HTML document,
125    /// helping to make up for those types which are not supported natively by this library. This
126    /// can be done by defining your own types that implement the [`Html`] trait.
127    ///
128    /// If you need a simple one-off, it may be more convenient to insert the element as a raw
129    /// string using [`with_raw`](HtmlContainer::with_raw) method instead
130    ///
131    /// # Example
132    /// ```
133    /// # use build_html::*;
134    /// #[derive(Debug)]
135    /// struct Span {
136    ///     content: String
137    /// }
138    ///
139    /// impl Span {
140    ///     pub fn new(content: impl ToString) -> Self {
141    ///         Span { content: content.to_string() }
142    ///     }
143    /// }
144    ///
145    /// impl Html for Span {
146    ///     fn to_html_string(&self) -> String {
147    ///         format!("<span>{}</span>", self.content)
148    ///     }
149    /// }
150    ///
151    /// let content = HtmlElement::new(HtmlTag::Div)
152    ///     .with_html(Span::new("inner"))
153    ///     .to_html_string();
154    /// assert_eq!(content, "<div><span>inner</span></div>");
155    /// ```
156    #[inline]
157    fn with_html<H: Html>(mut self, html: H) -> Self {
158        self.add_html(html);
159        self
160    }
161
162    /// Add the container to this HTML Container
163    ///
164    /// # Example
165    /// ```
166    /// # use build_html::*;
167    /// let mut content = Container::default();
168    /// content.add_container(Container::new(ContainerType::Main).with_paragraph("Inside"));
169    /// assert_eq!(content.to_html_string(), "<div><main><p>Inside</p></main></div>");
170    /// ```
171    #[inline]
172    fn add_container(&mut self, container: Container) {
173        self.add_html(container)
174    }
175
176    /// Nest the specified container within this container
177    ///
178    /// # Example
179    /// ```
180    /// # use build_html::*;
181    /// let content = Container::default()
182    ///     .with_header(1, "Content Outside")
183    ///     .with_container(
184    ///         Container::new(ContainerType::Main)
185    ///             .with_paragraph("Content Inside")
186    ///     )
187    ///     .to_html_string();
188    ///
189    /// assert_eq!(
190    ///     content,
191    ///     "<div><h1>Content Outside</h1><main><p>Content Inside</p></main></div>"
192    /// );
193    /// ```
194    #[inline]
195    fn with_container(self, container: Container) -> Self {
196        self.with_html(container)
197    }
198
199    /// Add the specified `Table` to this container
200    ///
201    /// # Example
202    /// ```
203    /// # use build_html::*;
204    /// let table = Table::from([
205    ///     [1, 2, 3],
206    ///     [4, 5, 6]
207    /// ]).with_header_row(['A', 'B', 'C']);
208    /// let mut container = HtmlElement::new(HtmlTag::Div);
209    /// container.add_table(table);
210    ///
211    /// assert_eq!(
212    ///     container.to_html_string(),
213    ///     concat!(
214    ///         "<div><table><thead>",
215    ///         "<tr><th>A</th><th>B</th><th>C</th></tr>",
216    ///         "</thead><tbody>",
217    ///         "<tr><td>1</td><td>2</td><td>3</td></tr>",
218    ///         "<tr><td>4</td><td>5</td><td>6</td></tr>",
219    ///         "</tbody></table></div>"
220    ///     )
221    /// );
222    /// ```
223    fn add_table(&mut self, table: Table) {
224        self.add_html(table);
225    }
226
227    /// Nest the specified `Table` within this container
228    ///
229    /// # Example
230    /// ```
231    /// # use build_html::*;
232    /// let content = HtmlElement::new(HtmlTag::Div)
233    ///     .with_table(
234    ///         Table::from(&[
235    ///             [1, 2, 3],
236    ///             [4, 5, 6]
237    ///         ])
238    ///         .with_header_row(&['A', 'B', 'C'])
239    ///     )
240    ///     .to_html_string();
241    ///
242    /// assert_eq!(
243    ///     content,
244    ///     concat!(
245    ///         "<div><table><thead>",
246    ///         "<tr><th>A</th><th>B</th><th>C</th></tr>",
247    ///         "</thead><tbody>",
248    ///         "<tr><td>1</td><td>2</td><td>3</td></tr>",
249    ///         "<tr><td>4</td><td>5</td><td>6</td></tr>",
250    ///         "</tbody></table></div>"
251    ///     )
252    /// );
253    /// ```
254    fn with_table(self, table: Table) -> Self {
255        self.with_html(table)
256    }
257
258    /// Adds a header tag with the designated level to this container
259    ///
260    /// # Example
261    /// ```
262    /// # use build_html::*;
263    /// let mut content = HtmlElement::new(HtmlTag::Div);
264    /// content.add_header(1, "Header Text");
265    /// assert_eq!(content.to_html_string(), r#"<div><h1>Header Text</h1></div>"#);
266    /// ```
267    fn add_header(&mut self, level: u8, text: impl ToString) {
268        self.add_header_attr(level, text, empty::<(&str, &str)>());
269    }
270
271    /// Adds a header tag with the designated level to this container
272    ///
273    /// # Example
274    /// ```
275    /// # use build_html::*;
276    /// let content = HtmlElement::new(HtmlTag::Div)
277    ///     .with_header(1, "Header Text")
278    ///     .to_html_string();
279    ///
280    /// assert_eq!(content, r#"<div><h1>Header Text</h1></div>"#);
281    /// ```
282    fn with_header(self, level: u8, text: impl ToString) -> Self {
283        self.with_header_attr(level, text, empty::<(&str, &str)>())
284    }
285
286    /// Adds a header tag with the designated level and attributes to this container.
287    ///
288    /// # Example
289    /// ```
290    /// # use build_html::*;
291    /// let mut content = HtmlElement::new(HtmlTag::Div);
292    /// content.add_header_attr(1, "Header Text", std::iter::once(("id", "main-header")));
293    /// assert_eq!(content.to_html_string(), r#"<div><h1 id="main-header">Header Text</h1></div>"#);
294    /// ```
295    fn add_header_attr<A, S>(&mut self, level: u8, text: impl ToString, attr: A)
296    where
297        A: IntoIterator<Item = (S, S)>,
298        S: ToString,
299    {
300        let tag = match level {
301            1 => HtmlTag::Heading1,
302            2 => HtmlTag::Heading2,
303            3 => HtmlTag::Heading3,
304            4 => HtmlTag::Heading4,
305            5 => HtmlTag::Heading5,
306            6 => HtmlTag::Heading6,
307            _ => panic!("'{}' is not a valid html heading level", level),
308        };
309
310        let mut element = HtmlElement::new(tag).with_child(HtmlChild::Raw(text.to_string()));
311        for (k, v) in attr {
312            element.add_attribute(k, v)
313        }
314
315        self.add_html(element);
316    }
317
318    /// Adds a header tag with the designated level and attributes to this container.
319    ///
320    /// # Example
321    /// ```
322    /// # use build_html::*;
323    /// let content = HtmlElement::new(HtmlTag::Div)
324    ///     .with_header_attr(1, "Header Text", std::iter::once(("id", "main-header")))
325    ///     .to_html_string();
326    ///
327    /// assert_eq!(content, r#"<div><h1 id="main-header">Header Text</h1></div>"#);
328    /// ```
329    fn with_header_attr<A, S>(mut self, level: u8, text: impl ToString, attr: A) -> Self
330    where
331        A: IntoIterator<Item = (S, S)>,
332        S: ToString,
333    {
334        self.add_header_attr(level, text, attr);
335        self
336    }
337
338    /// Adds an `<img>` tag to this container
339    ///
340    /// # Example
341    /// ```
342    /// # use build_html::*;
343    /// let mut content = HtmlElement::new(HtmlTag::Div);
344    /// content.add_image("myimage.png", "a test image");
345    /// assert_eq!(
346    ///     content.to_html_string(),
347    ///     r#"<div><img src="myimage.png" alt="a test image"/></div>"#
348    /// );
349    /// ```
350    fn add_image(&mut self, src: impl ToString, alt: impl ToString) {
351        self.add_image_attr(src, alt, empty::<(&str, &str)>());
352    }
353
354    /// Adds an `<img>` tag to this container
355    ///
356    /// # Example
357    /// ```
358    /// # use build_html::*;
359    /// let content = HtmlElement::new(HtmlTag::Div)
360    ///     .with_image("myimage.png", "a test image")
361    ///     .to_html_string();
362    ///
363    /// assert_eq!(content, r#"<div><img src="myimage.png" alt="a test image"/></div>"#);
364    /// ```
365    fn with_image(self, src: impl ToString, alt: impl ToString) -> Self {
366        self.with_image_attr(src, alt, empty::<(&str, &str)>())
367    }
368
369    /// Adds an `<img>` tag with the specified attributes to this container
370    ///
371    /// # Example
372    /// ```
373    /// # use build_html::*;
374    /// # use std::collections::BTreeMap;
375    /// let mut attrs = BTreeMap::new();
376    /// attrs.insert("id", "sample-image");
377    /// let mut content = HtmlElement::new(HtmlTag::Div);
378    /// content.add_image_attr("myimage.png", "a test image", attrs);
379    ///
380    /// assert_eq!(
381    ///     content.to_html_string(),
382    ///     r#"<div><img src="myimage.png" alt="a test image" id="sample-image"/></div>"#
383    /// );
384    /// ```
385    fn add_image_attr<A, S>(&mut self, src: impl ToString, alt: impl ToString, attr: A)
386    where
387        A: IntoIterator<Item = (S, S)>,
388        S: ToString,
389    {
390        let mut element = HtmlElement::new(HtmlTag::Image)
391            .with_attribute("src", src)
392            .with_attribute("alt", alt);
393        for (k, v) in attr {
394            element.add_attribute(k, v);
395        }
396
397        self.add_html(element);
398    }
399
400    /// Adds an `<img>` tag with the specified attributes to this container
401    ///
402    /// # Example
403    /// ```
404    /// # use build_html::*;
405    /// # use std::collections::BTreeMap;
406    /// let mut attrs = BTreeMap::new();
407    /// attrs.insert("id", "sample-image");
408    /// let content = HtmlElement::new(HtmlTag::Div)
409    ///     .with_image_attr("myimage.png", "a test image", attrs)
410    ///     .to_html_string();
411    ///
412    /// assert_eq!(
413    ///     content,
414    ///     r#"<div><img src="myimage.png" alt="a test image" id="sample-image"/></div>"#
415    /// );
416    /// ```
417    fn with_image_attr<A, S>(mut self, src: impl ToString, alt: impl ToString, attr: A) -> Self
418    where
419        A: IntoIterator<Item = (S, S)>,
420        S: ToString,
421    {
422        self.add_image_attr(src, alt, attr);
423        self
424    }
425
426    /// Adds an `<a>` tag to this container
427    ///
428    /// # Example
429    /// ```
430    /// # use build_html::*;
431    /// let mut content = HtmlElement::new(HtmlTag::Div);
432    /// content.add_link("https://rust-lang.org/", "Rust Homepage");
433    ///
434    /// assert_eq!(
435    ///     content.to_html_string(),
436    ///     r#"<div><a href="https://rust-lang.org/">Rust Homepage</a></div>"#
437    /// );
438    /// ```
439    fn add_link(&mut self, href: impl ToString, text: impl ToString) {
440        self.add_link_attr(href, text, empty::<(&str, &str)>());
441    }
442
443    /// Adds an `<a>` tag to this container
444    ///
445    /// # Example
446    /// ```
447    /// # use build_html::*;
448    /// let content = HtmlElement::new(HtmlTag::Div)
449    ///     .with_link("https://rust-lang.org/", "Rust Homepage")
450    ///     .to_html_string();
451    ///
452    /// assert_eq!(content, r#"<div><a href="https://rust-lang.org/">Rust Homepage</a></div>"#)
453    /// ```
454    fn with_link(self, href: impl ToString, text: impl ToString) -> Self {
455        self.with_link_attr(href, text, empty::<(&str, &str)>())
456    }
457
458    /// Adds an `<a>` tag with the specified attributes to this container
459    ///
460    /// # Example
461    /// ```
462    /// # use build_html::*;
463    /// let mut content = HtmlElement::new(HtmlTag::Div);
464    /// content.add_link_attr("https://rust-lang.org/", "Rust Homepage", [("class", "links")]);
465    ///
466    /// assert_eq!(
467    ///     content.to_html_string(),
468    ///     r#"<div><a href="https://rust-lang.org/" class="links">Rust Homepage</a></div>"#
469    /// );
470    /// ```
471    fn add_link_attr<A, S>(&mut self, href: impl ToString, text: impl ToString, attr: A)
472    where
473        A: IntoIterator<Item = (S, S)>,
474        S: ToString,
475    {
476        let mut element = HtmlElement::new(HtmlTag::Link)
477            .with_attribute("href", href)
478            .with_child(HtmlChild::Raw(text.to_string()));
479        for (k, v) in attr {
480            element.add_attribute(k, v);
481        }
482        self.add_html(element);
483    }
484
485    /// Adds an `<a>` tag with the specified attributes to this container
486    ///
487    /// # Example
488    /// ```
489    /// # use build_html::*;
490    /// let content = HtmlElement::new(HtmlTag::Div)
491    ///     .with_link_attr("https://rust-lang.org/", "Rust Homepage", [("class", "links")])
492    ///     .to_html_string();
493    ///
494    /// assert_eq!(
495    ///     content,
496    ///     r#"<div><a href="https://rust-lang.org/" class="links">Rust Homepage</a></div>"#
497    /// )
498    /// ```
499    fn with_link_attr<A, S>(mut self, href: impl ToString, text: impl ToString, attr: A) -> Self
500    where
501        A: IntoIterator<Item = (S, S)>,
502        S: ToString,
503    {
504        self.add_link_attr(href, text, attr);
505        self
506    }
507
508    /// Adds a `<p>` tag element to this Container
509    ///
510    /// # Example
511    /// ```
512    /// # use build_html::*;
513    /// let mut content = HtmlElement::new(HtmlTag::Div);
514    /// content.add_paragraph("This is sample paragraph text");
515    /// assert_eq!(content.to_html_string(), r#"<div><p>This is sample paragraph text</p></div>"#);
516    /// ```
517    fn add_paragraph(&mut self, text: impl ToString) {
518        self.add_paragraph_attr(text, empty::<(&str, &str)>());
519    }
520
521    /// Adds a `<p>` tag element to this Container
522    ///
523    /// # Example
524    /// ```
525    /// # use build_html::*;
526    /// let content = HtmlElement::new(HtmlTag::Div)
527    ///     .with_paragraph("This is sample paragraph text")
528    ///     .to_html_string();
529    ///
530    /// assert_eq!(content, r#"<div><p>This is sample paragraph text</p></div>"#);
531    /// ```
532    fn with_paragraph(self, text: impl ToString) -> Self {
533        self.with_paragraph_attr(text, empty::<(&str, &str)>())
534    }
535
536    /// Adds a `<p>` tag element with the specified attributes to this Container
537    ///
538    /// # Example
539    /// ```
540    /// # use build_html::*;
541    /// let mut content = HtmlElement::new(HtmlTag::Div);
542    /// content.add_paragraph_attr("This is sample paragraph text", [("class", "text")]);
543    /// assert_eq!(
544    ///     content.to_html_string(),
545    ///     r#"<div><p class="text">This is sample paragraph text</p></div>"#
546    /// );
547    /// ```
548    fn add_paragraph_attr<A, S>(&mut self, text: impl ToString, attr: A)
549    where
550        A: IntoIterator<Item = (S, S)>,
551        S: ToString,
552    {
553        let mut element =
554            HtmlElement::new(HtmlTag::ParagraphText).with_child(HtmlChild::Raw(text.to_string()));
555        for (k, v) in attr {
556            element.add_attribute(k, v);
557        }
558        self.add_html(element);
559    }
560
561    /// Adds a `<p>` tag element with the specified attributes to this Container
562    ///
563    /// # Example
564    /// ```
565    /// # use build_html::*;
566    /// let content = HtmlElement::new(HtmlTag::Div)
567    ///     .with_paragraph_attr("This is sample paragraph text", [("class", "text")])
568    ///     .to_html_string();
569    ///
570    /// assert_eq!(content, r#"<div><p class="text">This is sample paragraph text</p></div>"#)
571    /// ```
572    fn with_paragraph_attr<A, S>(mut self, text: impl ToString, attr: A) -> Self
573    where
574        A: IntoIterator<Item = (S, S)>,
575        S: ToString,
576    {
577        self.add_paragraph_attr(text, attr);
578        self
579    }
580
581    /// Adds a `<pre>` tag element to this container
582    ///
583    /// # Example
584    /// ```
585    /// # use build_html::*;
586    /// let mut content = HtmlElement::new(HtmlTag::Div);
587    /// content.add_preformatted("This | is   preformatted => text");
588    /// assert_eq!(
589    ///     content.to_html_string(),
590    ///     r#"<div><pre>This | is   preformatted => text</pre></div>"#
591    /// );
592    /// ```
593    fn add_preformatted(&mut self, text: impl ToString) {
594        self.add_preformatted_attr(text, empty::<(&str, &str)>());
595    }
596
597    /// Adds a `<pre>` tag element to this container
598    ///
599    /// # Example
600    /// ```
601    /// # use build_html::*;
602    /// let content = HtmlElement::new(HtmlTag::Div)
603    ///     .with_preformatted("This | is   preformatted => text")
604    ///     .to_html_string();
605    ///
606    /// assert_eq!(content, r#"<div><pre>This | is   preformatted => text</pre></div>"#);
607    /// ```
608    fn with_preformatted(self, text: impl ToString) -> Self {
609        self.with_preformatted_attr(text, empty::<(&str, &str)>())
610    }
611
612    /// Adds a `<pre>` tag element with the specified attributes to this container
613    ///
614    /// # Example
615    /// ```
616    /// # use build_html::*;
617    /// let mut content = HtmlElement::new(HtmlTag::Div);
618    /// content.add_preformatted_attr("This | is   preformatted => text", [("id", "code")]);
619    /// assert_eq!(
620    ///     content.to_html_string(),
621    ///     r#"<div><pre id="code">This | is   preformatted => text</pre></div>"#
622    /// );
623    /// ```
624    fn add_preformatted_attr<A, S>(&mut self, text: impl ToString, attr: A)
625    where
626        A: IntoIterator<Item = (S, S)>,
627        S: ToString,
628    {
629        let mut element = HtmlElement::new(HtmlTag::PreformattedText)
630            .with_child(HtmlChild::Raw(text.to_string()));
631        for (k, v) in attr {
632            element.add_attribute(k, v);
633        }
634        self.add_html(element);
635    }
636
637    /// Adds a `<pre>` tag element with the specified attributes to this container
638    ///
639    /// # Example
640    /// ```
641    /// # use build_html::*;
642    /// let content = HtmlElement::new(HtmlTag::Div)
643    ///     .with_preformatted_attr("This | is   preformatted => text", [("id", "code")])
644    ///     .to_html_string();
645    ///
646    /// assert_eq!(content, r#"<div><pre id="code">This | is   preformatted => text</pre></div>"#)
647    /// ```
648    fn with_preformatted_attr<A, S>(mut self, text: impl ToString, attr: A) -> Self
649    where
650        A: IntoIterator<Item = (S, S)>,
651        S: ToString,
652    {
653        self.add_preformatted_attr(text, attr);
654        self
655    }
656
657    /// Add raw content to the container. This content is pasted directly into the HTML
658    ///
659    /// This is intended to be used as an escape hatch for one-off insertions. If you want a more
660    /// reusable escape hatch, consider writing your own type implementing the [`Html`] trait. You
661    /// can then use [`add_html`](HtmlContainer::add_html) to insert boxed instances into the
662    /// container. See the documentation for that method for examples.
663    ///
664    /// # Example
665    /// ```
666    /// # use build_html::*;
667    /// let mut content = HtmlElement::new(HtmlTag::Div);
668    /// content.add_raw(r#"<video width="250"><source src="video.mp4" type="video/mp4"></video>"#);
669    /// assert_eq!(
670    ///     content.to_html_string(),
671    ///     r#"<div><video width="250"><source src="video.mp4" type="video/mp4"></video></div>"#
672    /// );
673    /// ```
674    fn add_raw(&mut self, content: impl ToString) {
675        self.add_html(content.to_string());
676    }
677
678    /// Add raw content to this container. The content is pasted directly into the HTML
679    ///
680    /// This is intended to be used as an escape hatch for one-off insertions. If you want a more
681    /// reusable escape hatch, consider writing your own type implementing the [`Html`] trait. You
682    /// can then use [`with_html`](HtmlContainer::with_html) to insert boxed instances into the
683    /// container. See the documentation for that method for examples.
684    ///
685    /// # Example
686    /// ```
687    /// # use build_html::*;
688    /// let content = HtmlElement::new(HtmlTag::Div)
689    ///     .with_raw(r#"<video width="250"><source src="video.mp4" type="video/mp4"></video>"#)
690    ///     .to_html_string();
691    ///
692    /// assert_eq!(
693    ///     content,
694    ///     r#"<div><video width="250"><source src="video.mp4" type="video/mp4"></video></div>"#
695    /// );
696    /// ```
697    fn with_raw(self, content: impl ToString) -> Self {
698        self.with_html(content.to_string())
699    }
700}