Some Tailwind CSS styles not being available in custom field #5293
-
When adding Tailwind classes to the Detail, Form and IndexField.vue files in a custom field, classes that are not already available in Nova do not appear to be processed by the Tailwind JIT engine, and are not available. To reproduceFresh laravel 9 and Nova 4.2.3 install Create new Custom Field with The build fails and as per issue #3856 run
Add a bg-green-200 class to the indexField.vue <template>
<span class="bg-green-200">{{ field.value }}</span>
</template>
<script>
export default {
props: ['resourceName', 'field'],
}
</script>Import the new field and add it to the fields of the User Resource: <?php
namespace App\Nova;
use Acme\ColorPicker\ColorPicker;
use Testing\Test\Test;
use Laravel\Nova\Fields\ID;
use Illuminate\Http\Request;
use Laravel\Nova\Fields\Text;
use Illuminate\Validation\Rules;
use Laravel\Nova\Fields\Gravatar;
use Laravel\Nova\Fields\Password;
use Laravel\Nova\Http\Requests\NovaRequest;
class User extends Resource
{
public static $model = \App\Models\User::class;
public static $title = 'name';
public static $search = [
'id', 'name', 'email',
];
public function fields(NovaRequest $request)
{
return [
ID::make()->sortable(),
Gravatar::make()->maxWidth(50),
Text::make('Name')
->sortable()
->rules('required', 'max:255'),
Text::make('Email')
->sortable()
->rules('required', 'email', 'max:254')
->creationRules('unique:users,email')
->updateRules('unique:users,email,{{resourceId}}'),
Password::make('Password')
->onlyOnForms()
->creationRules('required', Rules\Password::defaults())
->updateRules('nullable', Rules\Password::defaults()),
ColorPicker::make('name')
];
}Navigate within terminal to nova-components/ColorPicker and execute
Load the site up and navigate to the users resource Note there is no bg-green-200 applied around the final column FixesI have tried installed tailwindCSS as a dependency to the nova component itself (according to the installation instructions on the official tailwind page). I amended the fields.css file with This will apply the green background, but will mess up styling of nova elsewhere. For instance the create User button now moves off the page. This is something to do with the w-full Css rule created in the nova custom component dist/css/field.css file I have also tried installing tailwindCSS on my main app, and then pointing the tailwind.config.css file of the main app to include the custom field vue files, but this seems to have no affect './vendor/acme/ColorPicker/resources/js/components/*.vue',
'./nova-components/ColorPicker/resources/js/components/*.vue'Should Nova be instructing tailwind to parse the Vue files within the custom field for the classes which are used? It seems classes like bg-red-500 work because they are used elsewhere within nova. But classes not used within nova already are not being picked up by tailwinds JIT engine. Am I missing something? |
Beta Was this translation helpful? Give feedback.
Replies: 23 comments 3 replies
-
|
This is not a bug. We tried finding a way to include all the default Tailwind classes for Silver Surfer, but the JIT engine enables an infinite number of possibilities. For classes that aren't used (and thereby included in our CSS output), it's recommended to manually place those classes in your CSS file or Vue component |
Beta Was this translation helpful? Give feedback.
-
|
Ok. Is there an easy way to tell which classes are used in Nova's CSS output? For example, if I include the 'w-full' tailwind class in the custom field css then that messes with the styling of Nova. Also I wonder if this would be worth mentioning in the documentation to avoid others running into the same issue? |
Beta Was this translation helpful? Give feedback.
-
|
@davidhemphill I agree this is confusing, it should be mentioned in the doc. |
Beta Was this translation helpful? Give feedback.
-
|
@jimarick you can also install tailwindCSS with a prefix on all class so it will not mess up styling of nova elsewhere. In terminal webpack.mix.js tailwind.config.js field.css Then you can use |
Beta Was this translation helpful? Give feedback.
-
|
We did this, @desaintflorent, and yes, it works great, especially since Tailwind will only include the classes that you actually use in your own component. That is probably a small collection. The prefix is ugly but you get used to it. I wanted to note: dark mode does not work well with this approach. Nova uses the ‘class strategy’, which is not the default. You can enable it by adding You use this snippet in the main.js of your custom field, be sure to customize to your chosen prefix. if (localStorage.novaTheme === 'dark' || (!('novaTheme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('tw-dark')
} else {
document.documentElement.classList.remove('tw-dark')
}Unfortunately this only runs on page-load, so the user has to refresh after switching the preference, but it gets the important 95% of the dark mode done. |
Beta Was this translation helpful? Give feedback.
-
|
Thank's for the dark mode details, I didn't think about that. This should definitely be in the doc ! |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for the comments. Yes the key is Scoped Styles. I actually implemented an alternative method to the above 'prefix' technique, based on Jess Archer's Tweet I installed Tailwind directly to the custom component, and implemented the Important configuration in tailwind.config.js. Then in the vue components I simply wrapped my content in a div containing the 'my-component-scoped' class. MethodNavigate terminal to the custom field component (/nova-components/my-component/)
Tailwind.config.js (inside custom field) module.exports = {
content: [
"./resources/**/*.blade.php",
"./resources/**/*.js",
'./resources/js/**/*.vue',
],
theme: {
extend: {},
},
plugins: [],
important: '.my-component-scoped'
}webpack.mix.js (inside custom field) - (may need to change field.js to asset.js or other custom component name) field.css (inside custom field) (or asset.css or such like) Custom Field Vue components <template>
<div class="my-component-scoped">
<div class="h-5 z-0 ..."> </div>
</template>
OutcomeNow when compiled, all the css in nova-components/my-component/dist/css/field.css will be prefixed with the 'my-component-scoped' classname, and won't interfere with the rest of the app. .my-component-scoped .h-5 {
height: 1.25rem
}
.my-component-scoped .z-0 {
z-index: 0
}Not sure how this will interact with dark mode yet. But made it a lot easier for me than prefixing all my classes with 'tw-'. @davidhemphill I wonder if tailwind could be installed as a default dependency to all the custom fields, and a similar scoping technique could be included as default? |
Beta Was this translation helpful? Give feedback.
-
hi could you please explain what values do I have to add instead of asterisk below: |
Beta Was this translation helpful? Give feedback.
-
|
You don't need to add any values. Leave the ** which means all directories and * all files. https://stackoverflow.com/questions/46547540/meaning-of-a-double-star-in-a-file-path |
Beta Was this translation helpful? Give feedback.
-
|
@jimarick Your solution works perfect!!!Thanks a lot!! |
Beta Was this translation helpful? Give feedback.
-
Awesome tip @jimarick! Just so I could use some tailwind classes in my custom field without conflicting with the default nova theme. I think a deal like this should already come by default in the template, or at least have it in the documentation Thank you very much! |
Beta Was this translation helpful? Give feedback.
-
|
Glad it helped! Yes would be good to see it as an option when installing a custom component, or at least documented |
Beta Was this translation helpful? Give feedback.
-
|
Here is a way to interact with nova dark mode. The example use Vue 3 composition api.
module.exports = {
mode: 'jit',
content: [
'./resources/**/*{js,vue,blade.php}',
],
darkMode: 'class',
theme: {
extend: {},
},
plugins: [],
important: '.your-class'
}
<template>
<div class="your-class">
<div :class="{ dark: dark }">
<Head :title="__('Tool')"/>
/* content */
</div>
</div>
</template>
<script setup>
import { onMounted, onBeforeUnmount, ref } from 'vue'
const observer = ref(null)
const dark = ref(false)
onMounted(() => {
dark.value = document.documentElement.classList.contains('dark')
observer.value = new MutationObserver((records) => {
records.forEach((record) => {
dark.value = record.target.classList.contains('dark')
})
})
observer.value.observe(document.documentElement, {
attributes: true,
attributeFilter: ['class'],
childList: false,
characterData: false,
})
})
onBeforeUnmount(() => {
observer.value.disconnect()
observer.value = null
})
</script> |
Beta Was this translation helpful? Give feedback.
-
|
@davidhemphill With the update of nova to tailwindcss v3 it is now possible to include in the tailwind config of nova, the nova-components directory even if it doesn't exist in the project. Couldn't that be a solution now for missing classes from custom fields? |
Beta Was this translation helpful? Give feedback.
-
|
Nova's assets get compiled outside of an app, so there wouldn't be any content in a |
Beta Was this translation helpful? Give feedback.
-
|
@davidhemphill would you consider bundling tailwind by default in custom fields and components using scoped styles or prefixes as above? Or if not by default with a --tw flag when creating these components? |
Beta Was this translation helpful? Give feedback.
-
|
@davidhemphill If I do custom components with tailwind classes that are not part of nova then they wouldn't appear. I checked again and maybe my issue is that in the custom components tailwindcss is not part of it and that's why it is not showing up directly. |
Beta Was this translation helpful? Give feedback.
-
Hey :) do you have anymore thoughts on this? Or something in planning? We understand that there was no way of including all the Tailwind classes. At the same time it breaks our work. The creation of components is a feature in Nova. Thus, it would be convenient to use Tailwind without too many workarounds. Would be cool if this was mentioned in the upgrade guide too. |
Beta Was this translation helpful? Give feedback.
-
@jimarick |
Beta Was this translation helpful? Give feedback.
-
|
https://tailwindcss.com/docs/installation Just following docs |
Beta Was this translation helpful? Give feedback.
-
|
I found this solution for my environment: |
Beta Was this translation helpful? Give feedback.
-
it seems to be working in |
Beta Was this translation helpful? Give feedback.
-
|
There is no way to include all Tailwind CSS classes for Nova because the default configuration is too big for production. Tailwind CSS's JIT engine also enables infinite possibilities for additional CSS classes. This is by design. For classes that aren't used (and thereby included in our CSS output), it's recommended to manually place those classes in your CSS file or Vue component. Some Nova users have found using this PostCSS plugin to avoid borking Nova's styles to be the best option for using Tailwind CSS, while avoiding the problems with duplicated classes and class prefixes other community-suggested methods have: https://github.com/lukeraymonddowning/uniquestyles |
Beta Was this translation helpful? Give feedback.

There is no way to include all Tailwind CSS classes for Nova because the default configuration is too big for production. Tailwind CSS's JIT engine also enables infinite possibilities for additional CSS classes. This is by design.
For classes that aren't used (and thereby included in our CSS output), it's recommended to manually place those classes in your CSS file or Vue component.
Some Nova users have found using this PostCSS plugin to avoid borking Nova's styles to be the best option for using Tailwind CSS, while avoiding the problems with duplicated classes and class prefixes other community-suggested methods have: https://github.com/lukeraymonddowning/uniquestyles