Do you want to request a feature or report a bug?
๐ feature
Feature: What is your use case for such a feature?
๐จ Using a CSS framework without needing to create custom connectors/widgets
Feature: What is your proposed API entry? The new option to add? What is the behavior?
๐ฆ Maybe use the <Configure /> or the <InstantSearch /> components, for which we could add a prop to pass an object with CSS classes we want to apply based on default RIS classes. Example for the pagination using Bulma:
{
"ais-Pagination__root": "pagination-list",
"ais-Pagination__itemPrevious": "pagination-previous",
"ais-Pagination__itemNext": "pagination-next",
"ais-Pagination__item": "",
"ais-Pagination__itemLink": "pagination-link",
}
(In this case it would not be perfect because Bulma needs a wrapper with the .pagination class and RIS doesn't wrap the <ul>, but that's another problem ๐ )
Note: if you have another โeasyโ suggestion with an example to do the same thing, I'm happy to try!
What is the version you are using? Always use the latest one before opening a bug issue.
๐
Latest
Today the statement about this is: if you need to modify the markup/classnames, then you should use the connectors.
Due to the instability about how you can do css with React, we removed our first approach (that among other things, allowed you to change classnames) until we can came up with something that feel solid.
You said that you want something easy to style our component. What's currently your main difficulties while styling them through our classnames? Maybe there's something we can investigate here.
Thanks for the answer @mthuret! I was afraid that the best was to use a connector but was hoping for something simpler (although connectors are probably not that complicated, just need to try ^^)
I can't use existing RIS classes because I want to use an external CSS framework and I need to use custom class names. The solution I've been offered is to use SASS for style "inheritance/include" but I'm not using SASS right now and it seems a bit hacky.
Happy to talk more about it if you think it might be interesting. I'll leave a feedback after trying the connector way ๐
Thanks again!
For reference, see also https://github.com/algolia/instantsearch.js/issues/2089
After years of doing CSS at different scales, the way I found the easiest to write and maintain is using an approach similar to tachyons.css: hundred of re-usable classes that do each one thing and one thing only.
You end-up writing HTML like this: <div class="pa3 bg-red white ml3 tc">. Each of those class has one responsability, and once you get used to the terseness it's actually pretty easy to mentally visualize what it mean. (_Here it's "padding all round of 3 units", "red background", "white text", "margin left of 3 units" and "text centered"_)
There is no inheritance, each class only affect the element it's on. Re-reading code after 6 months is pretty easy as all the relevant code is right there, along with the HTML. You very rarely have to write additional CSS. All you need is to load tachyons.css and you're good to go.
(Tachyons has many more advantages like a cohesize size scale, a11y color palette, breakpoints, etc, but I only focus on the part important here: styling is done by adding several classes to elements)
I'd like to keep that way of doing CSS when using React InstantSearch, the benefits in terms of maintainance for me have been huge in the past year. I'll have a look at the connectors to see how this could be done.
@mthuret @pixelastic what about testing with a component-level option where we can pass a set of classes for each (sub-)component? Basically it would use my initial suggestion but at a more granular level.
On the implementation side, it would mean checking the presence of this attribute and add the provided classes for the RIS component with the specified class, e.g.
{
"ais-Pagination__root": "pagination-list pa3 bg-red",
"ais-Pagination__itemPrevious": "pagination-previous",
"ais-Pagination__itemNext": "pagination-next",
"ais-Pagination__item": "",
"ais-Pagination__itemLink": "pagination-link white ml3 tc",
}
In the meantime, SASS inheritance could be an alternative (not the most DRY, but cool for POCs)?
.ais-Pagination__itemLink {
@extend .pagination-link;
@extend .white;
@extend .ml3;
@extend .tc;
}
Would go with only using the "element" as key of that object, and if that key is present, add an extra class. It's not ideal since it's an object prop, but otoh, I think it would be reasonably simple to inject in the bem function (If provided includes same key as in function, then output two. The props.classes or whatever can then be passed through from the component to the function.
@redox: SCSS @extend has a few drawbacks when it comes to selectors priorities. It's a hack that can be used as a workaround on a small project, but it will lead to issues in large scale. For the record, that's how I solved my issue so far, but it makes me write CSS in a completly different way than the rest of my app, just for RIS. In the long term, it makes the approach brittle as RIS is adding friction to the way I style the app.
I like @julienpa approach (not sure I understand what you're saying @Haroenv, though :| ), as it would let me avoid writing new CSS and reuse my existing classes.
Simple proposal for you to review:
const myClasses = {
'Pagination__root': 'youpi kai'
};
<InstantSearch
CSSClassNames={
(className, defaultCompute) =>
if (myClasses[className] !== undefined) {
return myClasses[className];
}
return defaultCompute(className);
}
>
</InstantSearch>
So what should I have to pass, as a user? the myClasses object or the defaultCompute method called for every time a class if to be added?
You would have to pass a CSSClassNames method where you can map to anything or use the default class name.
This also allows you to easily add any prefix.
@vvo does it mean that with the code snippet you shared, we could override classes of any RIS component just by updating the myClasses object?
What would the CSSClassNames method signature be? From what I understand it only needs to take the initial RIS classname as input and return a new set of classes. I don't understand what the defaultCompute is doing here.
This is a proposal only for discussing it, it's a prop on the main InstantSearch component that you can use to customize CSS class names.
we could override classes of any RIS component just by updating the myClasses object?
What would the CSSClassNames method signature be?
<InstantSearch
toCSSClassName={
(params, defaultBemClassName) => { // params: object, defaultBemClassName: function
// params.block: 'pagination'
// params.element 'root'
// params.modifier
console.log(defaultBemClassName(params));
// Pagination__root
return params.block + '--' params.element + ' cool-root'; // we're sending two css class names
}
>
</InstantSearch>
You can do pretty much anything with that, from overriding the default prefix to changing the BEM notation or providing more CSS classes to one element (bootstrap)
I like the idea! Basically you expose the internal BEM function and you allow the user to either use it literally or to customize the output?
Oh I see. That's a terrific idea, gives a lot of power to integrate with any library that way. A function would let a users add classes, change them, apply conditional changes. I love it.
Most helpful comment
This is a proposal only for discussing it, it's a prop on the main InstantSearch component that you can use to customize CSS class names.
You can do pretty much anything with that, from overriding the default prefix to changing the BEM notation or providing more CSS classes to one element (bootstrap)