{
diff --git a/packages/html/Cargo.toml b/packages/html/Cargo.toml
index 72c93b8b8..800dcf873 100644
--- a/packages/html/Cargo.toml
+++ b/packages/html/Cargo.toml
@@ -27,6 +27,7 @@ rfd = { version = "0.14", optional = true }
futures-channel = { workspace = true }
serde_json = { version = "1", optional = true }
tracing.workspace = true
+rustversion = "1.0.17"
[dependencies.web-sys]
optional = true
@@ -50,6 +51,9 @@ features = [
[dev-dependencies]
serde_json = "1"
+dioxus = { workspace = true }
+dioxus-web = { workspace = true }
+tokio = { workspace = true, features = ["time"] }
[features]
default = ["serialize", "mounted", "eval"]
diff --git a/packages/html/docs/common_event_handler_errors.md b/packages/html/docs/common_event_handler_errors.md
new file mode 100644
index 000000000..b3935006a
--- /dev/null
+++ b/packages/html/docs/common_event_handler_errors.md
@@ -0,0 +1,133 @@
+## Compiler errors you may run into while using event handlers
+
+
+function requires argument type to outlive `'static`
+
+Event handler in Dioxus need only access data that can last for the entire lifetime of the application. That generally means data that is moved into the closure. **If you get this error, you may have forgotten to add `move` to your closure.**
+
+Broken component:
+
+```rust, compile_fail
+# use dioxus::prelude::*;
+// We return an Element which can last as long as the component is on the screen
+fn App() -> Element {
+ // Signals are `Copy` which makes them very easy to move into `'static` closures like event handlers
+ let state = use_signal(|| "hello world".to_string());
+
+ rsx! {
+ button {
+ // ❌ Without `move`, rust will try to borrow the `state` signal which fails because the state signal is dropped at the end of the function
+ onclick: |_| {
+ println!("You clicked the button! The state is: {state}");
+ },
+ "Click me"
+ }
+ }
+ // The state signal is dropped here, but the event handler still needs to access it
+}
+```
+
+Fixed component:
+
+```rust, no_run
+# use dioxus::prelude::*;
+fn App() -> Element {
+ let state = use_signal(|| "hello world".to_string());
+
+ rsx! {
+ button {
+ // ✅ The `move` keyword tells rust it can move the `state` signal into the closure. Since the closure owns the signal state, it can read it even after the function returns
+ onclick: move |_| {
+ println!("You clicked the button! The state is: {state}");
+ },
+ "Click me"
+ }
+ }
+}
+```
+
+
+
+
+use of moved value: `your_value` value used here after move
+
+Data in rust has a single owner. If you run into this error, you have likely tried to move data that isn't `Copy` into two different closures. **You can fix this issue by making your data `Copy` or calling `clone` on it before you move it into the closure.**
+
+Broken component:
+
+```rust, compile_fail
+# use dioxus::prelude::*;
+// `MyComponent` accepts a string which cannot be copied implicitly
+#[component]
+fn MyComponent(string: String) -> Element {
+ rsx! {
+ button {
+ // ❌ We are moving the string into the onclick handler which means we can't access it elsewhere
+ onclick: move |_| {
+ println!("{string}");
+ },
+ "Print hello world"
+ }
+ button {
+ // ❌ Since we already moved the string, we can't move it into the onclick handler again. This will cause a compiler error
+ onclick: move |_| {
+ println!("{string}");
+ },
+ "Print hello world again"
+ }
+ }
+}
+```
+
+You can fix this issue by either:
+
+- Making your data `Copy` with `ReadOnlySignal`:
+
+```rust, no_run
+# use dioxus::prelude::*;
+// `MyComponent` accepts `ReadOnlySignal` which implements `Copy`
+#[component]
+fn MyComponent(string: ReadOnlySignal) -> Element {
+ rsx! {
+ button {
+ // ✅ Because the `string` signal is `Copy`, we can copy it into the closure while still having access to it elsewhere
+ onclick: move |_| println!("{}", string),
+ "Print hello world"
+ }
+ button {
+ // ✅ Since `string` is `Copy`, we can move it into the onclick handler again
+ onclick: move |_| println!("{}", string),
+ "Print hello world again"
+ }
+ }
+}
+```
+
+- Calling `clone` on your data before you move it into the closure:
+
+```rust, no_run
+# use dioxus::prelude::*;
+// `MyComponent` accepts a string which doesn't implement `Copy`
+#[component]
+fn MyComponent(string: String) -> Element {
+ rsx! {
+ button {
+ // ✅ The string only has one owner. We could move it into this closure, but since we want to use the string in other closures later, we will clone it instead
+ onclick: {
+ // Clone the string in a new block
+ let string = string.clone();
+ // Then move the cloned string into the closure
+ move |_| println!("{}", string)
+ },
+ "Print hello world"
+ }
+ button {
+ // ✅ We don't use the string after this closure, so we can just move it into the closure directly
+ onclick: move |_| println!("{}", string),
+ "Print hello world again"
+ }
+ }
+}
+```
+
+
diff --git a/packages/html/docs/eval.md b/packages/html/docs/eval.md
new file mode 100644
index 000000000..673a13f14
--- /dev/null
+++ b/packages/html/docs/eval.md
@@ -0,0 +1,125 @@
+# Communicating with JavaScript
+
+You can use the `eval` function to execute JavaScript code in your application with the desktop, mobile, web or liveview renderers. Eval takes a block of JavaScript code (that may be asynchronous) and returns a `UseEval` object that you can use to send data to the JavaScript code and receive data from it.
+
+
+
+## Safety
+
+Please be careful when executing JavaScript code with `eval`. You should only execute code that you trust. **This applies especially to web targets, where the JavaScript context has access to most, if not all of your application data.** Running untrusted code can lead to a [cross-site scripting](https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting) (XSS) vulnerability.
+
+
+
+```rust
+use dioxus::prelude::*;
+
+fn App() -> Element {
+ rsx! {
+ button {
+ onclick: move |_| async move {
+ // Eval is a global function you can use anywhere inside Dioxus. It will execute the given JavaScript code.
+ let result = eval(r#"console.log("Hello World");
+ return "Hello World";"#);
+
+ // You can use the `await` keyword to wait for the result of the JavaScript code.
+ println!("{:?}", result.await);
+ },
+ "Log Hello World"
+ }
+ }
+}
+```
+
+## Sending data to JavaScript
+
+When you execute JavaScript code with `eval`, you can pass data to it by formatting the value into the JavaScript code or sending values to the `UseEval` channel.
+
+```rust
+use dioxus::prelude::*;
+
+fn app() -> Element {
+ rsx! {
+ button {
+ onclick: move |_| {
+ // You can pass initial data to the eval function by formatting it into the JavaScript code.
+ const LOOP_COUNT: usize = 10;
+ let eval = eval(&format!(r#"for(let i = 0; i < {LOOP_COUNT}; i++) {{
+ // You can receive values asynchronously with the the `await dioxus.recv()` method.
+ let value = await dioxus.recv();
+ console.log("Received", value);
+ }}"#));
+
+ // You can send values from rust to the JavaScript code with the `send` method on the object returned by `eval`.
+ for i in 0..LOOP_COUNT {
+ eval.send(i.into()).unwrap();
+ }
+ },
+ "Log Count"
+ }
+ }
+}
+```
+
+## Sending data from JavaScript
+
+The `UseEval` struct also contains methods for receiving values you send from JavaScript. You can use the `dioxus.send()` method to send values to the JavaScript code and the `UseEval::recv()` method to receive values from the JavaScript code.
+
+```rust
+use dioxus::prelude::*;
+
+fn app() -> Element {
+ rsx! {
+ button {
+ onclick: move |_| async move {
+ // You can send values from rust to the JavaScript code by using the `send` method on the object returned by `eval`.
+ let mut eval = eval(r#"for(let i = 0; i < 10; i++) {
+ // You can send values asynchronously with the `dioxus.send()` method.
+ dioxus.send(i);
+ }"#);
+
+ // You can receive values from the JavaScript code with the `recv` method on the object returned by `eval`.
+ for _ in 0..10 {
+ let value = eval.recv().await.unwrap();
+ println!("Received {}", value);
+ }
+ },
+ "Log Count"
+ }
+ }
+}
+```
+
+## Interacting with the DOM with Eval
+
+You can also use the `eval` function to execute JavaScript code that reads or modifies the DOM. If you want to interact with the mounted DOM, you need to use `eval` inside the [`dioxus_hooks::use_effect`] hook which runs after the component has been mounted.
+
+```rust
+use dioxus::prelude::*;
+
+const SCRIPT: &str = r#"
+ let element = document.getElementById("my-element");
+ element.innerHTML = "Hello World";
+ return element.getAttribute("data-count");
+"#;
+
+fn app() -> Element {
+ // ❌ You shouldn't run eval in the body of a component. This will run before the component has been mounted
+ // eval(SCRIPT);
+
+ // ✅ You should run eval inside an effect or event. This will run after the component has been mounted
+ use_effect(move || {
+ spawn(async {
+ let count = eval(SCRIPT).await;
+ println!("Count is {:?}", count);
+ });
+ });
+
+
+ rsx! {
+ div {
+ id: "my-element",
+ "data-count": "123",
+ }
+ }
+}
+```
diff --git a/packages/html/docs/event_handlers.md b/packages/html/docs/event_handlers.md
new file mode 100644
index 000000000..9c867906a
--- /dev/null
+++ b/packages/html/docs/event_handlers.md
@@ -0,0 +1,86 @@
+# Event Handlers
+
+Event Handlers let you react to user input in your application. In Dioxus, event handlers accept a closure that is called when the event occurs:
+
+```rust, no_run
+use dioxus::prelude::*;
+
+fn App() -> Element {
+ rsx! {
+ button {
+ // The `onclick` event accepts a closure with the signature `fn(Event)`
+ onclick: |event_data| println!("clicked! I got the event data: {event_data:?}"),
+ "Click me"
+ }
+ }
+}
+```
+
+## Event Lifetimes
+
+Events take a closure with the `'static` lifetime. This means that the closure can only access data that either exists for the entire lifetime of the application, or data that you move into the closure.
+
+State in dioxus is `copy` which makes it very easy to move into `'static` closures like event handlers:
+
+```rust, no_run
+# use dioxus::prelude::*;
+let mut count = use_signal(|| 0);
+
+rsx! {
+ button {
+ // Since we added the `move` keyword, the closure will move the `count` signal into the closure
+ onclick: move |_| {
+ // This will panic because the `count` signal is not in scope
+ count.set(count() + 1);
+ },
+ "Click me"
+ }
+};
+```
+
+If you need to access data that is not `Copy`, you may need to clone the data before you move it into the closure:
+
+```rust, no_run
+# use dioxus::prelude::*;
+// String is not `Copy`
+let string = "hello world".to_string();
+
+rsx! {
+ button {
+ // The string only has one owner. We could move it into this closure, but since we want to use the string in other closures later, we will clone it instead
+ onclick: {
+ // Clone the string in a new block
+ let string = string.clone();
+ // Then move the cloned string into the closure
+ move |_| println!("{}", string)
+ },
+ "Print hello world"
+ }
+ button {
+ // We don't use the string after this closure, so we can just move it into the closure directly
+ onclick: move |_| println!("{}", string),
+ "Print hello world again"
+ }
+};
+```
+
+## Async Event Handlers
+
+In addition to closures that return nothing, you can also use async closures to handle events. If you return an async block from an event handler, dioxus will automatically spawn it:
+
+```rust, no_run
+use dioxus::prelude::*;
+
+fn App() -> Element {
+ rsx! {
+ button {
+ // The `onclick` event can also accept a closure that returns an async block
+ onclick: move |_| async move {
+ tokio::time::sleep(std::time::Duration::from_secs(1)).await;
+ println!("You clicked the button one second ago!");
+ },
+ "Click me"
+ }
+ }
+}
+```
diff --git a/packages/html/src/attribute_groups.rs b/packages/html/src/attribute_groups.rs
index cc4fbb09e..08546a13c 100644
--- a/packages/html/src/attribute_groups.rs
+++ b/packages/html/src/attribute_groups.rs
@@ -29,12 +29,21 @@ macro_rules! mod_method_mapping {
(
$matching:ident;
$(#[$attr:meta])*
- $name:ident: $lit:literal, $ns:literal;
+ $name:ident: $lit:literal in $ns:literal;
) => {
if $matching == stringify!($name) {
return Some(($lit, Some($ns)));
}
};
+ (
+ $matching:ident;
+ $(#[$attr:meta])*
+ $name:ident in $ns:literal;
+ ) => {
+ if $matching == stringify!($name) {
+ return Some((stringify!($name), Some($ns)));
+ }
+ };
}
#[cfg(feature = "html-to-rsx")]
@@ -60,12 +69,21 @@ macro_rules! html_to_rsx_attribute_mapping {
(
$matching:ident;
$(#[$attr:meta])*
- $name:ident: $lit:literal, $ns:literal;
+ $name:ident: $lit:literal in $ns:literal;
) => {
if $matching == stringify!($lit) {
return Some(stringify!($name));
}
};
+ (
+ $matching:ident;
+ $(#[$attr:meta])*
+ $name:ident in $ns:literal;
+ ) => {
+ if $matching == stringify!($name) {
+ return Some(stringify!($name));
+ }
+ };
}
macro_rules! mod_methods {
@@ -77,7 +95,7 @@ macro_rules! mod_methods {
$fn_html_to_rsx:ident;
$(
$(#[$attr:meta])*
- $name:ident $(: $($arg:literal),*)*;
+ $name:ident $(: $js_name:literal)? $(in $ns:literal)?;
)+
) => {
$(#[$mod_attr])*
@@ -85,7 +103,29 @@ macro_rules! mod_methods {
use super::*;
$(
$(#[$attr])*
- pub const $name: AttributeDiscription = mod_methods! { $name $(: $($arg),*)*; };
+ ///
+ /// ## Usage in rsx
+ ///
+ /// ```rust, ignore
+ /// # use dioxus::prelude::*;
+ #[doc = concat!("let ", stringify!($name), " = \"value\";")]
+ ///
+ /// rsx! {
+ /// // Attributes need to be under the element they modify
+ /// div {
+ /// // Attributes are followed by a colon and then the value of the attribute
+ #[doc = concat!(" ", stringify!($name), ": \"value\"")]
+ /// }
+ /// div {
+ /// // Or you can use the shorthand syntax if you have a variable in scope that has the same name as the attribute
+ #[doc = concat!(" ", stringify!($name), ",")]
+ /// }
+ /// };
+ /// ```
+ $(
+ #[doc(alias = $js_name)]
+ )?
+ pub const $name: AttributeDiscription = mod_methods! { $name $(: $js_name)? $(in $ns)?; };
)*
}
@@ -94,7 +134,7 @@ macro_rules! mod_methods {
$(
mod_method_mapping! {
attr;
- $name$(: $($arg),*)*;
+ $name $(: $js_name)? $(in $ns)?;
}
)*
None
@@ -106,7 +146,7 @@ macro_rules! mod_methods {
$(
html_to_rsx_attribute_mapping! {
html;
- $name$(: $($arg),*)*;
+ $name $(: $js_name)? $(in $ns)?;
}
)*
None
@@ -116,7 +156,10 @@ macro_rules! mod_methods {
};
// Rename the incoming ident and apply a custom namespace
- ( $name:ident: $lit:literal, $ns:literal; ) => { ($lit, Some($ns), false) };
+ ( $name:ident: $lit:literal in $ns:literal; ) => { ($lit, Some($ns), false) };
+
+ // Custom namespace
+ ( $name:ident in $ns:literal; ) => { (stringify!($name), Some($ns), false) };
// Rename the incoming ident
( $name:ident: $lit:literal; ) => { ($lit, None, false ) };
@@ -140,11 +183,11 @@ mod_methods! {
///
- accesskey: "accesskey";
+ accesskey;
///
- autocapitalize: "autocapitalize";
+ autocapitalize;
///
@@ -159,25 +202,38 @@ mod_methods! {
/// Classes allow CSS and Javascript to select and access specific elements via the class selectors or
/// functions like the DOM method document.getElementsByClassName.
///
- /// ## Example
+ /// ## Multiple Classes
///
- /// ### HTML:
- /// ```html
- /// Above point sounds a bit obvious. Remove/rewrite?
+ /// If you include multiple classes in a single element dioxus will automatically join them with a space.
+ ///
+ /// ```rust
+ /// # use dioxus::prelude::*;
+ /// rsx! {
+ /// div {
+ /// class: "my-class",
+ /// class: "my-other-class"
+ /// }
+ /// };
/// ```
///
- /// ### CSS:
- /// ```css
- /// .note {
- /// font-style: italic;
- /// font-weight: bold;
- /// }
+ /// ## Optional Classes
///
- /// .editorial {
- /// background: rgb(255, 0, 0, .25);
- /// padding: 10px;
- /// }
+ /// You can include optional attributes with an unterminated if statement as the value of the attribute. This is very useful for conditionally applying css classes:
+ ///
+ /// ```rust
+ /// # use dioxus::prelude::*;
+ /// rsx! {
+ /// div {
+ /// class: if true {
+ /// "my-class"
+ /// },
+ /// class: if false {
+ /// "my-other-class"
+ /// }
+ /// }
+ /// };
/// ```
+ ///
///
class;
@@ -271,1222 +327,1222 @@ mod_methods! {
// This roughly follows the html spec
///
- align_content: "align-content", "style";
+ align_content: "align-content" in "style";
///
- align_items: "align-items", "style";
+ align_items: "align-items" in "style";
///
- align_self: "align-self", "style";
+ align_self: "align-self" in "style";
///
- alignment_adjust: "alignment-adjust", "style";
+ alignment_adjust: "alignment-adjust" in "style";
///
- alignment_baseline: "alignment-baseline", "style";
+ alignment_baseline: "alignment-baseline" in "style";
///
- all: "all", "style";
+ all in "style";
///
- alt: "alt", "style";
+ alt in "style";
///
- animation: "animation", "style";
+ animation in "style";
///
- animation_delay: "animation-delay", "style";
+ animation_delay: "animation-delay" in "style";
///
- animation_direction: "animation-direction", "style";
+ animation_direction: "animation-direction" in "style";
///
- animation_duration: "animation-duration", "style";
+ animation_duration: "animation-duration" in "style";
///
- animation_fill_mode: "animation-fill-mode", "style";
+ animation_fill_mode: "animation-fill-mode" in "style";
///
- animation_iteration_count: "animation-iteration-count", "style";
+ animation_iteration_count: "animation-iteration-count" in "style";
///
- animation_name: "animation-name", "style";
+ animation_name: "animation-name" in "style";
///
- animation_play_state: "animation-play-state", "style";
+ animation_play_state: "animation-play-state" in "style";
///
- animation_timing_function: "animation-timing-function", "style";
+ animation_timing_function: "animation-timing-function" in "style";
///
- azimuth: "azimuth", "style";
+ azimuth in "style";
///
- backdrop_filter: "backdrop-filter", "style";
+ backdrop_filter: "backdrop-filter" in "style";
///
- backface_visibility: "backface-visibility", "style";
+ backface_visibility: "backface-visibility" in "style";
///
- background: "background", "style";
+ background in "style";
///
- background_attachment: "background-attachment", "style";
+ background_attachment: "background-attachment" in "style";
///
- background_clip: "background-clip", "style";
+ background_clip: "background-clip" in "style";
///
- background_color: "background-color", "style";
+ background_color: "background-color" in "style";
///
- background_image: "background-image", "style";
+ background_image: "background-image" in "style";
///
- background_origin: "background-origin", "style";
+ background_origin: "background-origin" in "style";
///
- background_position: "background-position", "style";
+ background_position: "background-position" in "style";
///
- background_repeat: "background-repeat", "style";
+ background_repeat: "background-repeat" in "style";
///
- background_size: "background-size", "style";
+ background_size: "background-size" in "style";
///
- background_blend_mode: "background-blend-mode", "style";
+ background_blend_mode: "background-blend-mode" in "style";
///
- baseline_shift: "baseline-shift", "style";
+ baseline_shift: "baseline-shift" in "style";
///
- bleed: "bleed", "style";
+ bleed in "style";
///
- bookmark_label: "bookmark-label", "style";
+ bookmark_label: "bookmark-label" in "style";
///
- bookmark_level: "bookmark-level", "style";
+ bookmark_level: "bookmark-level" in "style";
///
- bookmark_state: "bookmark-state", "style";
+ bookmark_state: "bookmark-state" in "style";
///
- border: "border", "style";
+ border in "style";
///
- border_color: "border-color", "style";
+ border_color: "border-color" in "style";
///
- border_style: "border-style", "style";
+ border_style: "border-style" in "style";
///
- border_width: "border-width", "style";
+ border_width: "border-width" in "style";
///
- border_bottom: "border-bottom", "style";
+ border_bottom: "border-bottom" in "style";
///
- border_bottom_color: "border-bottom-color", "style";
+ border_bottom_color: "border-bottom-color" in "style";
///
- border_bottom_style: "border-bottom-style", "style";
+ border_bottom_style: "border-bottom-style" in "style";
///
- border_bottom_width: "border-bottom-width", "style";
+ border_bottom_width: "border-bottom-width" in "style";
///
- border_left: "border-left", "style";
+ border_left: "border-left" in "style";
///
- border_left_color: "border-left-color", "style";
+ border_left_color: "border-left-color" in "style";
///
- border_left_style: "border-left-style", "style";
+ border_left_style: "border-left-style" in "style";
///
- border_left_width: "border-left-width", "style";
+ border_left_width: "border-left-width" in "style";
///
- border_right: "border-right", "style";
+ border_right: "border-right" in "style";
///
- border_right_color: "border-right-color", "style";
+ border_right_color: "border-right-color" in "style";
///
- border_right_style: "border-right-style", "style";
+ border_right_style: "border-right-style" in "style";
///
- border_right_width: "border-right-width", "style";
+ border_right_width: "border-right-width" in "style";
///
- border_top: "border-top", "style";
+ border_top: "border-top" in "style";
///
- border_top_color: "border-top-color", "style";
+ border_top_color: "border-top-color" in "style";
///
- border_top_style: "border-top-style", "style";
+ border_top_style: "border-top-style" in "style";
///
- border_top_width: "border-top-width", "style";
+ border_top_width: "border-top-width" in "style";
///
- border_collapse: "border-collapse", "style";
+ border_collapse: "border-collapse" in "style";
///
- border_image: "border-image", "style";
+ border_image: "border-image" in "style";
///
- border_image_outset: "border-image-outset", "style";
+ border_image_outset: "border-image-outset" in "style";
///
- border_image_repeat: "border-image-repeat", "style";
+ border_image_repeat: "border-image-repeat" in "style";
///
- border_image_slice: "border-image-slice", "style";
+ border_image_slice: "border-image-slice" in "style";
///
- border_image_source: "border-image-source", "style";
+ border_image_source: "border-image-source" in "style";
///
- border_image_width: "border-image-width", "style";
+ border_image_width: "border-image-width" in "style";
///
- border_radius: "border-radius", "style";
+ border_radius: "border-radius" in "style";
///
- border_bottom_left_radius: "border-bottom-left-radius", "style";
+ border_bottom_left_radius: "border-bottom-left-radius" in "style";
///
- border_bottom_right_radius: "border-bottom-right-radius", "style";
+ border_bottom_right_radius: "border-bottom-right-radius" in "style";
///
- border_top_left_radius: "border-top-left-radius", "style";
+ border_top_left_radius: "border-top-left-radius" in "style";
///
- border_top_right_radius: "border-top-right-radius", "style";
+ border_top_right_radius: "border-top-right-radius" in "style";
///
- border_spacing: "border-spacing", "style";
+ border_spacing: "border-spacing" in "style";
///
- bottom: "bottom", "style";
+ bottom in "style";
///
- box_decoration_break: "box-decoration-break", "style";
+ box_decoration_break: "box-decoration-break" in "style";
///
- box_shadow: "box-shadow", "style";
+ box_shadow: "box-shadow" in "style";
///
- box_sizing: "box-sizing", "style";
+ box_sizing: "box-sizing" in "style";
///
- box_snap: "box-snap", "style";
+ box_snap: "box-snap" in "style";
///
- break_after: "break-after", "style";
+ break_after: "break-after" in "style";
///
- break_before: "break-before", "style";
+ break_before: "break-before" in "style";
///
- break_inside: "break-inside", "style";
+ break_inside: "break-inside" in "style";
///
- buffered_rendering: "buffered-rendering", "style";
+ buffered_rendering: "buffered-rendering" in "style";
///
- caption_side: "caption-side", "style";
+ caption_side: "caption-side" in "style";
///
- clear: "clear", "style";
+ clear in "style";
///
- clear_side: "clear-side", "style";
+ clear_side: "clear-side" in "style";
///
- clip: "clip", "style";
+ clip in "style";
///
- clip_path: "clip-path", "style";
+ clip_path: "clip-path" in "style";
///
- clip_rule: "clip-rule", "style";
+ clip_rule: "clip-rule" in "style";
///
- color: "color", "style";
+ color in "style";
///
- color_adjust: "color-adjust", "style";
+ color_adjust: "color-adjust" in "style";
///
- color_correction: "color-correction", "style";
+ color_correction: "color-correction" in "style";
///
- color_interpolation: "color-interpolation", "style";
+ color_interpolation: "color-interpolation" in "style";
///
- color_interpolation_filters: "color-interpolation-filters", "style";
+ color_interpolation_filters: "color-interpolation-filters" in "style";
///
- color_profile: "color-profile", "style";
+ color_profile: "color-profile" in "style";
///
- color_rendering: "color-rendering", "style";
+ color_rendering: "color-rendering" in "style";
///
- column_fill: "column-fill", "style";
+ column_fill: "column-fill" in "style";
///
- column_gap: "column-gap", "style";
+ column_gap: "column-gap" in "style";
///
- column_rule: "column-rule", "style";
+ column_rule: "column-rule" in "style";
///
- column_rule_color: "column-rule-color", "style";
+ column_rule_color: "column-rule-color" in "style";
///
- column_rule_style: "column-rule-style", "style";
+ column_rule_style: "column-rule-style" in "style";
///
- column_rule_width: "column-rule-width", "style";
+ column_rule_width: "column-rule-width" in "style";
///
- column_span: "column-span", "style";
+ column_span: "column-span" in "style";
///
- columns: "columns", "style";
+ columns in "style";
///
- column_count: "column-count", "style";
+ column_count: "column-count" in "style";
///
- column_width: "column-width", "style";
+ column_width: "column-width" in "style";
///
- contain: "contain", "style";
+ contain in "style";
///
- content: "content", "style";
+ content in "style";
///
- counter_increment: "counter-increment", "style";
+ counter_increment: "counter-increment" in "style";
///
- counter_reset: "counter-reset", "style";
+ counter_reset: "counter-reset" in "style";
///
- counter_set: "counter-set", "style";
+ counter_set: "counter-set" in "style";
///
- cue: "cue", "style";
+ cue in "style";
///
- cue_after: "cue-after", "style";
+ cue_after: "cue-after" in "style";
///
- cue_before: "cue-before", "style";
+ cue_before: "cue-before" in "style";
///
- cursor: "cursor", "style";
+ cursor in "style";
///
- direction: "direction", "style";
+ direction in "style";
///
- display: "display", "style";
+ display in "style";
///
- display_inside: "display-inside", "style";
+ display_inside: "display-inside" in "style";
///