diff --git a/examples/Cargo.toml b/examples/Cargo.toml
index 7e6808fe..de03ddbe 100644
--- a/examples/Cargo.toml
+++ b/examples/Cargo.toml
@@ -8,6 +8,7 @@ members = [
"colors_rgb",
"demo",
"demo2",
+ "hyperlinks",
"minimal",
"pong",
"shared",
diff --git a/examples/hyperlinks/Cargo.toml b/examples/hyperlinks/Cargo.toml
new file mode 100644
index 00000000..c8471d1a
--- /dev/null
+++ b/examples/hyperlinks/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "hyperlinks"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[dependencies]
+ratzilla.workspace = true
+console_error_panic_hook.workspace = true
diff --git a/examples/hyperlinks/index.html b/examples/hyperlinks/index.html
new file mode 100644
index 00000000..15ad59f2
--- /dev/null
+++ b/examples/hyperlinks/index.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+ Ratzilla Hyperlinks
+
+
+
+
diff --git a/examples/hyperlinks/src/main.rs b/examples/hyperlinks/src/main.rs
new file mode 100644
index 00000000..56a61292
--- /dev/null
+++ b/examples/hyperlinks/src/main.rs
@@ -0,0 +1,92 @@
+use std::io;
+
+use ratzilla::{
+ ratatui::{
+ layout::{Alignment, Constraint, Layout, Rect},
+ prelude::{Color, Stylize, Terminal},
+ widgets::{Block, BorderType, Clear, Paragraph},
+ },
+ widgets::Hyperlink,
+ DomBackend, WebRenderer,
+};
+
+fn main() -> io::Result<()> {
+ std::panic::set_hook(Box::new(console_error_panic_hook::hook));
+
+ let terminal = Terminal::new(DomBackend::new()?)?;
+ terminal.draw_web(|frame| {
+ frame.render_widget(Clear, frame.area());
+
+ let [card] = Layout::vertical([Constraint::Length(9)])
+ .flex(ratzilla::ratatui::layout::Flex::Center)
+ .areas(frame.area());
+ let [card] = Layout::horizontal([Constraint::Length(44)])
+ .flex(ratzilla::ratatui::layout::Flex::Center)
+ .areas(card);
+
+ frame.render_widget(
+ Block::bordered()
+ .border_type(BorderType::Rounded)
+ .title(" Aliasable Hyperlinks ".bold())
+ .border_style(Color::LightGreen),
+ card,
+ );
+
+ let inner = card.inner(ratzilla::ratatui::layout::Margin {
+ vertical: 1,
+ horizontal: 2,
+ });
+ let [intro, docs, repo, plain] = Layout::vertical([
+ Constraint::Length(2),
+ Constraint::Length(1),
+ Constraint::Length(1),
+ Constraint::Length(1),
+ ])
+ .spacing(0)
+ .areas(inner);
+
+ frame.render_widget(
+ Paragraph::new("DOM links use native browser anchors.")
+ .alignment(Alignment::Left),
+ intro,
+ );
+ render_link(
+ frame,
+ docs,
+ "Docs: ",
+ Hyperlink::with_label(
+ "Ratatui rendering guide".black().on_cyan().bold(),
+ "https://ratatui.rs/concepts/rendering/under-the-hood/",
+ ),
+ );
+ render_link(
+ frame,
+ repo,
+ "Repo: ",
+ Hyperlink::with_label(
+ "ratzilla on GitHub".black().on_yellow().italic(),
+ "https://github.com/ratatui/ratzilla",
+ ),
+ );
+ render_link(
+ frame,
+ plain,
+ "Website: ",
+ Hyperlink::new("https://ratatui.rs".light_cyan().underlined()),
+ );
+ });
+ Ok(())
+}
+
+fn render_link(
+ frame: &mut ratzilla::ratatui::Frame<'_>,
+ area: Rect,
+ label: &str,
+ link: Hyperlink<'_>,
+) {
+ let [prefix, suffix] =
+ Layout::horizontal([Constraint::Length(label.len() as u16), Constraint::Min(0)])
+ .areas(area);
+ frame.render_widget(Paragraph::new(label), prefix);
+ frame.render_widget(link, suffix);
+}
diff --git a/src/backend/dom.rs b/src/backend/dom.rs
index f43846d4..138f7f70 100644
--- a/src/backend/dom.rs
+++ b/src/backend/dom.rs
@@ -25,6 +25,7 @@ use crate::{
error::Error,
event::{KeyEvent, MouseEvent},
render::WebEventHandler,
+ widgets::hyperlink_state,
CursorShape,
};
@@ -78,6 +79,10 @@ pub struct DomBackend {
initialized: Rc>,
/// Cells.
cells: Vec,
+ /// Current cell contents.
+ buffer: Vec,
+ /// Current hyperlink targets for each cell.
+ hyperlinks: Vec |