Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

class vs className consumption #942

Closed
thomasmattheussen opened this issue Nov 22, 2017 · 9 comments
Closed

class vs className consumption #942

thomasmattheussen opened this issue Nov 22, 2017 · 9 comments
Labels

Comments

@thomasmattheussen
Copy link

After reading #103

I would think that this would work:

const componentA = () => {
    return (
        <ComponentB class="yyy">
            Hello World
        </ComponentB>
    )
}

const componentB = () => {
    const { children, className, ...other } = this.props;

    return (
        <div class={ className } { ...other }>
            { children }
        </div>
    )
};

// Expected output: <div class="yyy">Hello World</div>
// Real output: <div>Hello World</div>

In componentB, className is undefined when componentA passes class as the prop (the preact recommendation), whereas in componentB this.props.class does equal "yyy"

In my understanding, in componentB, I should be able to use this.props.className as well as this.props.class regardless of how the prop is passed in componentA. Am I under the wrong assumption?

@lukeed
Copy link
Member

lukeed commented Nov 22, 2017

Finally, I should mention that Preact will happily consume className props/attributes if you use them. The JSX reviver simply changes the name to class and continues on as it would have if you'd used class.

You can use class or className, whichever you want. But Preact doesn't convert className to class as a property. It accepts both/either for the rendering DOM attribute on plain VDOM elements. See tests.

The props will look exactly as you define them, so it's best to pick one and stay consistent 😄

@thomasmattheussen
Copy link
Author

So if I wanted to make a component that's consumable by both React and Preact, it would be best to check for both properties?

@andybons
Copy link
Contributor

class is only supported in React if you’re using Web Components[1], so if you want maximum interop, I would go with className.

[1] https://reactjs.org/docs/dom-elements.html#classname

@thomasmattheussen
Copy link
Author

Sure, but devs that use Preact get the recommendation to use class instead of classname. It would be unintuitive/inconsistent for them to use classname for this specific component, as opposed to the rest of their app.

So I'm wondering if I should use some pattern like this:

import { h } from 'preact';
import cx from 'classnames';

const ComponentA = ({ class: c1, className: c2, ...other }) => {
    return (
        <div class={ cx('component-a', c1, c2) } { ...other } />
    );
};

export default ComponentA;

@developit
Copy link
Member

This is one of the things preact-compat does that we might want to put into a preact-compat-lite package.

Here's a tiny plugin for Preact that makes className a strict alias of class bidirectionally using a getter/setter pair. Should solve your problem nicely:

import { options } from 'preact';

const classNameDescriptor = {
	enumerable: true,
	configurable: true,
	get() { return this.class; },
	set(value) { this.class = value; }
};

let old = options.vnode;
options.vnode = vnode => {
	let a = vnode.attributes;
	if (a && a.class) {
		Object.defineProperty(a, 'className', classNameDescriptor);
	}
	if (old) old(vnode);
};

@bodaso
Copy link

bodaso commented Dec 17, 2017

I'm running into a classnames issue with sass modules in Preact:

// Card component
import { h, Component } from "preact";
import cx from "classnames";
import style from "./style";

export const Card = () => {
  return (
    <div class={style.card}>
      <div class={cx(style.image, "image-item")} />
      <div class={style.body} />
    </div>
  );
};

// in style.scss
.card {
  .image-item {
    margin-bottom: 23px;
  }
}

The specified margin-bottom css does not get applied, any ideas?

@developit
Copy link
Member

developit commented Dec 20, 2017

@BODAZ you need to reference it as style['image-item']:

// Card component
import { h, Component } from "preact";
import cx from "classnames";
import style from "./style";

export const Card = () => {
  return (
    <div class={style.card}>
      <div class={cx(style.image, style['image-item'])} />
      <div class={style.body} />
    </div>
  );
};

// in style.scss
.card {
  .image-item {
    margin-bottom: 23px;
  }
}

Better to post these types of unrelated questions on Slack or StackOverflow btw.

@marvinhagemeister
Copy link
Member

@developit Agree, I think this belongs into preact-compat, not into core. The issue should be moved there.

@mitranim
Copy link
Contributor

Just destructure-rename it:

function InnerView({class: className}) {/* ... */}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants