[csswg-drafts] [css-values] value() function (#7869)

brandonmcconnell has just created a new issue for https://github.com/w3c/csswg-drafts:

== [css-values] value() function ==
# The problem
CSS doesn't yet have a way to retrieve the `value` property for an input/select/textarea/etc or to use/reuse those values in any useful way, since we can't pass values up the cascade, and form field elements generally (ever?) don't have descendant elements.

It's possible to set the `value` attribute on a form field, but it's often the case that when the value of that field changes the attribute itself remains the same, standing more so as a reference to the field's initial value than an indicator of its "live" value.

In other words, without using JS, access to a field's value is impossible.

# Description of the proposal
I propose adding a `value()` function which returns the active or "live" value of anyh value-holding element, namely form fields. The syntax would be fairly similar to the existing & future `attr()` syntax.

### Background
As mentioned in "The problem" section above, since we can't pass values up the cascade and form field elements don't have descendant elements, in order for this function to be useful, it needs a way to expose these values in such a way that they can be re-used throughout the cascade, even in other areas not neighboring the fields themselves.

For this reason, this PR should be treated as a stacked PR atop #7866

[PR #7866](https://github.com/w3c/csswg-drafts/issues/7866) provides a way for any CSS values to be stored at a global scope and be re-used as needed.

### Syntax
```css
value([syntax?])
```

### Usage
The single syntax argument would be optional, equipping a developer to set the intended syntax for the result, where leaving it empty would use the field's intrinsic syntax.

For example, using…
* `value(number)` or `value()` on `input[type="number"]` or `input[type="range"]` would result in a number value, since `number` is the intrinsic syntax for those input types
* `value(string)` on  `input[type="number"]` or `input[type="range"]` would result in the field's value but parsed as a string which could then be used anywhere a string could be used (e.g. the `content` property of a pseudo-element)
* `value(string)` or `value()` on any of the following types would result in a string/text value, since that is the intrinsic and intended syntax for those input types
  * `input[type="text"]`
  * `input[type="email"]`
  * `input[type="tel"]`
  * `input[type="search"]`
  * `input[type="url"]`
  * `input[type="radio"]:checked`
  * `input[type="checkbox"]:checked`
  * `select > option:selected`
  * `textarea`
* `value(number)` on any of these ☝🏼 however would result in the field's value parsed as a number. In any case where that numeric parsing fails, that declaration is ignored and skipped. When the pasring succeeds, the number returned can be used anywhere a number would normally be accepted.
* `value(color)` or `value()` on `input[type="color"]` would result in a color value, since `color` is the intrinsic syntax for that input types

# Considerations
* When first tossing around this idea, I thought it might be more complicated to account for `select`, `checkbox`, and `radio` button values, but after giving it more thought, I think those should work as desired naturally. The key differenceβ€”as mentioned in the "Usage" examples aboveβ€”is that a developer should store the value for the active (`:checked` or `:selected`) field itself, not just all `select`/`checkbox`/`radio` fields, like this:
  ```css
  [type="checkbox"]:checked {
    --value: value();
  }
  [type="radio"]:checked {
    --value: value();
  }
  select > option:selected {
    --value: value();
  }
  ```
* While attribute modifications can be tracked using `MutationObserver.observe`, `value` changes would likely be more appropriately tracked using the `input` and `change` events.
* There are many input types which don't (yet) have a CSS representation or equivalent syntax. It would be worth discussing that a bit deeper to see how/if those should be handled and evaluated.

# A more complete example

How might this look in practice?

```
* different values for input's value attr vs. property ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┬┄┄┄┄┄┄┄┄┄┐
                                                                            ┆         ┆
html ━┓                                                                     ┆         ┆
      ┣━ head                                                               ┆         ┆
      ┗━ body ━┓                                                            ┆         ┆
               ┣━ div ━┓                                                    ┆         ┆
               ┃       ┣━ span                                              ┆         ┆
               ┃       ┗━ div#progress                                      ┆         ┆
               ┗━ form ━┓                                                   ┆         ┆
                        ┗━ input[type="range"][min=0][max=100][step=1][value=10]{value: 30}
```

```css
@property --range-min {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
  global: true;
}
@property --range-max {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
  global: true;
}
@property --range-val {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
  global: true;
}
span::before {
  content: "The current value, " var(--range-val) ", is between " var(--range-min) " and " var(--range-max);
}
div#progress {
  --offset-max: var(--range-max) - var(--range-min);
  --offset-val: var(--range-val) - var(--range-min);
  --stop: calc((var(--offset-val) / var(--offset-max)) * 100%);
  background: linear-gradient(to right, black var(--stop), white var(--stop));
}
form > input[type="range"]#range {
  --range-min: attr(min number);
  --range-max: attr(max number);
  --range-val: value();
}
```

This example demonstrates how you might use `value()` paired with `attr()` and global variables to take a range input's value, min, and max values and create a label and makeshift progress bar using them, all done using only CSS.

This is just one example, and many more could be made, and I have no doubt I'll create several more as I comtiue to iterate on this concept and work toward a viable implementation.

Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/7869 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Wednesday, 12 October 2022 00:21:05 UTC