1

Basically I want to create a reusable component which can be slightly modified from the outside in react:

SomewhereElse.tsx

...
<FooComponent width={200}>
...

FooComponent.tsx

interface IFooProps {
  //default width of 150px
  width?: 150;
  //default margin of 5px
  margin?: 5;
}

interface IFooState{
  checked: boolean;
}

class FooComponent extends Component<IFooProps, IFooState> {
    constructor(props: IFooProps) {
        super(props);
        ...
    }

...

    render(): ReactElement {
        return (
          <div className="foo-component"
              data-width={this.props.width + 'px'}
          >
          ...

FooComponent.scss

.foo-component {
    ...
    width: attr(data-width length);
    ...

But it always gives me the following error when running the application (chrome):

errorinchrome

... Please consider that I need a "number" as property because I am doing some calculations based on that number for some of the inner components so everything fits together.

EDIT:

Using "style" is not working for me because I have some ::before ::after features in my scss which are broken when using style because they occasionally modify "right:" based on the width.

For better understanding, this is my base: https://www.sitepoint.com/react-toggle-switch-reusable-component/

Pwnstar
  • 2,333
  • 2
  • 29
  • 52
  • `data-width`? What is this for..? – wentjun May 29 '20 at 13:44
  • It might be easier to reset --var() css customproperties to update the rule's value . possible related post https://stackoverflow.com/questions/59231839/material-ui-global-css-variables & https://stackoverflow.com/questions/46323117/using-html-data-attributes-as-css-variable-i-e-text-shadow – G-Cyrillus May 29 '20 at 13:47
  • @wentjun it is an attribute selector. you can use them to dynamically define values for different components or to insert values specifically for a component. – Pwnstar Jun 02 '20 at 07:24
  • @Spektakulatius Yepp I know it is..! I was just wondering why did you use the data- attribute since it is not commonly used in React since there are other React-friendly ways to bind data/styles – wentjun Jun 02 '20 at 07:26

4 Answers4

2

To answer your question

Please find a solution with attribute selector or tell me that it is not possible because of X reasons (link to docs in best-case).

No, although it would be super useful, according to my research it's currently not possible:

MDN about CSS attr():

Note: The attr() function can be used with any CSS property, but support for properties other than content is experimental, and support for the type-or-unit parameter is sparse.

According to caniuse.com about css3-attr, the ability to use attr() on any CSS property (besides content, and to use it for non-string values (e.g. numbers, colors) via <type_or_unit> as defined per "CSS Values and Units Level 3" is currently unsupported by all browsers.

See also the statement on the current draft for "CSS Values and Units Module Level 4":

The following features are at-risk, and may be dropped during the CR period: toggle(), attr() [...]

(Source: https://drafts.csswg.org/css-values/#status)

In the Chromium issue, I found a link to an interesting resource I wasn't aware of: web-platform-tests dashboard for css-values. Take a look at the (failing) tests prefixed with attr-, especially attr-length-valid.html and attr-px-valid.html.

But there is hope: the Chromium team recently (05/15/2020) posted an Intent to Implement and Ship: CSS advanced attr() function

Implement the augmentation to attr() specified in CSS Level 4, namely, allowing various types (besides ) and usage in all CSS properties (besides pseudo-element 'content').

Note: CSS Level 4 has made substantial revisions to attr() compared to Level 3 to ease the implementation. We'll follow CSS4. [...]

Motivation: This is a highly requested feature, with 77 stars at crbug.com/246571. [...]

Chromium tracking Issue 246571: Implement CSS3 attribute / attr references )

Firefox also show recent activity, see Firefox tracking Bug 435426 [meta] Implement CSS Values 3 extensions to attr(), there they at least are referring to Chromiums current efforts.

(WebKit Bug 26609 - Support CSS3 attr() function shows no activity, which could be a deal-breaker)

Community
  • 1
  • 1
Sebastian B.
  • 2,141
  • 13
  • 21
1

As suggested from G-Cyrillus I have found a possible solution using CSS custom properties. Unfortunetly I did not find a solution using attribute selector so I could stick to one solution type.

Add your custom properties in the scss file "parent" class like:

.foo-component {
    --customwidth: 150px;
    --custommargin: 5px;

    width: var(--customwidth, 150px);
    ...
    &-inner {
        margin-left: var(--custommargin, 5px);
    }
    ...
}

After you declared the customproperty it's possible to use it with var(<propertyname>, <initialvalue>).

In React you slightly can modify the render() like:

 render(): ReactElement {
    //set the custom properties for width, margin and slider position
    let cssProperties = {};
    cssProperties['--customwidth'] = this.props.width == null ? '150px' : this.props.width + 'px';
    cssProperties['--custommargin'] = this.props.margin == null ? '150px' : this.props.margin + 'px';
    cssProperties['--switchposition'] = (this.props.width == null ? 115 : this.props.width - 35) + 'px';

    return (
      <div className="foo-component" style={cssProperties}>
      ...
}

Which will work for every component seperatly.

Pwnstar
  • 2,333
  • 2
  • 29
  • 52
0

An easier way would be using inline style:

       return (
          <div className="foo-component"
              style=`width:${this.props.width};`
          >
KnxPwr
  • 56
  • 4
  • Have you considered to also use something like CSS-IN-JS or styled-components? if you want to use props directly on your components for styling purposes it will surely speed you up – KnxPwr May 29 '20 at 13:56
  • Sorry that does not fulfill my needs, because I am using stuff like ::before and ::after which changes the value sometimes. So using a fixed "width" breaks that behavior. – Pwnstar May 29 '20 at 13:56
  • Have you tried to use document.documentElement.style.setProperty? Maybe you can override your CSS variable on component load. For more info about this: https://davidwalsh.name/css-variables-javascript – KnxPwr May 29 '20 at 14:12
0

With attr you need to specify the attribute by providing the selector in your scss styles

.foo-component[data-width] {
    ...
    width: attr(data-width length);
    ...

If you have multiple such attribute you can write them like

.foo-component[data-width][data-margin] {
    ...
    width: attr(data-width length);
    margin: attr(data-margin number);
    ...

Please check the MDN docs for more details

Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400