JSS CSS Classes - How to identify correct ones to use?

Product: PowerShell Universal
Version: 3.9.0

In the styles section of dashboards, there are a bunch of styles named .jss## (see below) which seem to be generated on the fly with the dashboard, thus the names change from session to session. I’ve found that these are generated by JSS, which is used as a dependency of MaterialUI’s legacy Style solution, according to their documentation.

image

These styles are applied to different elements throughout the page/dashboard, and I can’t seem to figure out how to determine what goes where… These are applied on top of any custom ClassName applied to an element, and it completely breaks the continuity of things when you need to use a mix of custom elements, and such.

I can provide more information if need be, but this is definitely a bit of a thorn in the site. I see someone else asked about this a while back but had no response. (Style main class .jss2 - PowerShell Universal - Ironman Software Forums)

You’re right that those styles are created on the fly using a react library that does this. If you want to override those styles, you’ll need to target the class names are static. MUIv4 places static class names across all their components on varying levels of the HTML.

Here’s an example of overriding a MUI alert’s background style. You may need to use !important to override styles because the jjs# style may come after the MUI built in style.

You can also use themes to override the MUI theme colors. These match the class names and you more or less need to translate the class name into a hashtable that is provided to the theme engine. I have an example of doing that with a button here.

It’s also what’s described here: https://docs.powershelluniversal.com/userinterfaces/dashboards/themes#component-overrides

Outside of MUI components, if you are using other customer components, your mileage will vary from component to component. It will depend on if they are using JSS generated styles or class names.

1 Like

Yea that all makes sense. Part of what I was trying to do was add the ‘download’ attribute to the buttons, as well as toggle the hidden attribute based on other activity in the dashboard. This proved more complicated than I imagined. Ultimately I built the Switch-UDElementAttribute function below, which I could use to toggle that (and the hidden attribute) in the way I needed. I also built a couple of other functions that I found useful for specifically interacting with elements in ways that the built in functionality just didn’t quite seem to support in the way I needed.

Switch-UDElementAttribute

function Switch-UDElementAttribute {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]
        $Id,
        [Parameter(Mandatory)]
        [string]
        $AttributeName
    )
    begin {
        Write-Debug "Enter [$($PSCmdlet.MyInvocation.MyCommand.Name)]..."
        $Javascript = @"
var elem; 
elem = document.getElementById('{0}'); 
elem.toggleAttribute('{1}');
"@ -f $Id, $AttributeName
    }
    process {
        Invoke-UDJavaScript -JavaScript $Javascript
    }
    end {
        Write-Debug "Exit [$($PSCmdlet.MyInvocation.MyCommand.Name)]..."
    }
}
Set-Alias -Name Toggle-UDElementAttribute -Value Switch-UDElementAttribute

Set-UDElementAttribute

function Set-UDELementAttribute {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]
        $Id,
        [Parameter(Mandatory)]
        [string]
        $AttributeName,
        [Parameter(Mandatory)]
        [object]
        $Value
    )
    begin {
        Write-Debug "Enter [$($PSCmdlet.MyInvocation.MyCommand.Name)]..."
        if ($value -is [string]) {
            $value = "'$Value'"
        }
        $Javascript = @"
var elem; 
elem = document.getElementById('{0}'); 
elem.setAttribute('{1}',{2});
"@ -f $Id, $AttributeName, $Value
    }
    process {
        Invoke-UDJavaScript -JavaScript $Javascript
    }
    end {
        Write-Debug "Exit [$($PSCmdlet.MyInvocation.MyCommand.Name)]..."
    }
}

Set-UDElementClassMember

function Set-UDElementClassMember {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]
        $Id,
        [Parameter(Mandatory)]
        [string]
        $MemberName,
        [Parameter()]
        [ValidateSet('Add', 'Remove', 'Replace')]
        [string]
        $Function
    )
    DynamicParam {
        if ($Function -eq 'Replace') {         
            $ParameterAttribute = [System.Management.Automation.ParameterAttribute]::new()
            $AttributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
            $AttributeCollection.Add($ParameterAttribute)
            $NewValueParam = [System.Management.Automation.RuntimeDefinedParameter]::new('NewValue', [string], $AttributeCollection)
            
            $paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::New()
            $paramDictionary.Add('NewValue', $NewValueParam)
            return $paramDictionary
        }
    }
    begin {
        Write-Debug "Enter [$($PSCmdlet.MyInvocation.MyCommand.Name)]..."
        #region set variables not set in dynamic params
        $CommonParameters = [System.Management.Automation.Cmdlet]::CommonParameters
        foreach ($key in $PSBoundParameters.Keys.Where{ $PSitem -notin $CommonParameters }) {
            $KeyVariableExists = Get-Variable -Name $key -ErrorAction SilentlyContinue
            if ( -not $KeyVariableExists ) {
                if ($PSBoundParameters.Item($key) -is [array]) {
                    $object = New-Object $($PSBoundParameters.Item($key).GetType().UnderlyingSystemType.Name) -ArgumentList 0 # This will auto-grow as we add values
                    # $object = New-Object $($PSBoundParameters.Item($key).GetType().UnderlyingSystemType.Name) -ArgumentList $PSBoundParameters.Item($key).Count
                    $null = New-Variable -Name $key -Value $object
                    $PSBoundParameters.Item($key) | ForEach-Object {
                        $thisValue = $PSItem
                        $thisVariableValue = Get-Variable -Name $key -ValueOnly
                        $thisVariableValue += $thisValue
                        Set-Variable -Name $key -Value $thisVariableValue
                    }
                } else {
                    New-Variable -Name $key -Value $PSBoundParameters.Item($key)
                }
            }
        }
        #endregion set variables not set in dynamic params
        
#         $ReplaceJavascript = @"
# var elem; 
# elem = document.getElementById('{0}'); 
# var edit = elem.getAttribute('class');
# edit = edit.replace('{1}','{2}')
# elem.setAttribute('class',edit)
# console.log('{0}.class = ' + edit);
# "@ -f $Id, $MemberName, $NewValue
        $ReplaceJavascript = @"
var elem; 
elem = document.getElementById('{0}'); 
var edit = elem.className;
edit = edit.replace('{1}','{2}')
elem.className = edit;
console.log('{0}.class = ' + edit);
"@ -f $Id, $MemberName, $NewValue

        $AddJavascript = @"
var elem; 
elem = document.getElementById('{0}'); 
var edit = elem.getAttribute('class');
console.log('{0}.class = ' + edit);
var editA = edit.split(' ');
void editA.push('{1}');
var editOut = editA.join(' ');
elem.setAttribute('class',editOut)
console.log('
{0}.class = ' + editOut);
"@ -f $Id, $MemberName
    }
    process {
        if ($Function -eq 'Add') {
            Invoke-UDJavaScript -JavaScript $AddJavascript
        } else {
            Invoke-UDJavaScript -JavaScript $ReplaceJavascript
        }
    }
    end {
        Write-Debug "Exit [$($PSCmdlet.MyInvocation.MyCommand.Name)]..."
    }
}