Can HTML tag attributes be accessed in CSS within the Shadow-DOM?

As I work on developing a custom component using StencilJS, I find myself needing to adjust the outline behavior when users navigate through it with either a keyboard or mouse.

My component employs ShadowDOM and I aim to extract an HTML tag attribute from the CSS styling.

To capture keyboard and mouse events, the attributes of the tag are populated by what-input (https://github.com/ten1seven/what-input).

I experimented with CSS Selectors such as [data-whatintent=keyboard] and html[data-whatintent=keyboard], but unfortunately, they did not yield the desired results.

This is the snippet of my HTML tag where the data-whatintent attribute resides:

<html dir="ltr" lang="en" data-whatinput="keyboard" data-whatintent="mouse">

  <my-custom-component></my-custom-component>

</html>

Below is an excerpt from my CSS file:

[data-whatintent=keyboard] *:focus {
  outline: solid 2px #1A79C6;
}

It is essential for me to leverage the value of the data-whatintent attribute in my ShadowDOM CSS rules to effectively style the component's outline according to my specifications.

Answer №1

Supersharp's response is accurate, although it does not consist of StencilJS code and host-context support may be unreliable (especially in Firefox and likely in IE11).

You can 'migrate' the attribute to the host element and then utilize the selector within the host component style:

TSX:

private intent: String;

componentWillLoad() {
    this.intent = document.querySelector('html').getAttribute('data-whatintent');
}

hostData() {
    return {
        'data-whatintent': this.intent
    };
}

SCSS:

:host([data-whatintent="keyboard"]) *:focus {
    outline: solid 2px #1A79C6;
}

If the data-whatintent attribute changes dynamically, make it a property of the component and have the listener function update your component. You can also use the property to add or remove classes to the host for styling, or continue using the attribute selector.

TSX:

@Prop({ mutable: true, reflectToAtrr: true }) dataWhatintent: String;

componentWillLoad() {
    this.dataWhatintent = document.querySelector('html').getAttribute('data-whatintent');
}

hostData() {
    return {
        class: { 
            'data-intent-keyboard': this.dataWhatintent === 'keyboard' 
        }
    };
}

SCSS:

:host(.data-intent-keyboard) *:focus {
    outline: solid 2px #1A79C6;
}

Document's keyboard and mouse event handler:

function intentHandler(event: Event) {
    const intent = event instanceof KeyboardEvent ? 'keyboard' : 'mouse';
    document.querySelectorAll('my-custom-component').forEach(
        el => el.setAttribute('data-whatintent', intent)
    );
}

Answer №2

To apply a CSS style in a Shadow DOM depending on the context where the Custom Element is used, you can leverage the use of :host-context().

customElements.define( 'my-custom-component', class extends HTMLElement {
    constructor() {
        super()
        this.attachShadow( { mode: 'open' } )
            .innerHTML = `
              <style>
                :host-context( [data-whatinput=keyboard] ) *:focus {
                   outline: solid 2px #1A79C6;
                }
              </style>
              <input value="Hello">`
    }
} )         
           
<html dir="ltr" lang="en" data-whatinput="keyboard" data-whatintent="mouse">

  <my-custom-component></my-custom-component>

</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using an external font in JavaFX CSS

Can you style a font with CSS in a JavaFX application? I have an FXML scene and corresponding CSS file. In Java code, you can set a font using the setFont method: text.setFont(Font.loadFont("file:resources/fonts/SourceSansPro-Bold.ttf", 12)); I've t ...

Fading Out with JQuery

My page contains about 30 same-sized divs with different classes, such as: .mosaic-block, .events, .exhibitions, .gallery, .sponsors, .hospitality, .workshops, .lectures { background:rgba(0, 0, 0, .30); float:left; position:relative; overf ...

The elusive Ajax seems to be slipping through our grasp,

I am currently working on a website app to display the availability of PCs in my University using JSON data from the University website and AJAX. I am facing an issue where it shows all the MACs for the first room, but returns undefined for others. Since t ...

Tips on storing the amount of time a user devotes to answering questions on my form into a database

I am facing an issue with storing the "duration" in my database. The "duration" I aim to store is the time spent by the user answering a question I created. When they click the submit button, I want to save the duration they spent in the database. Below i ...

Invoke a function of a child component that resides within the <ng-content> tag of its parent component

Check out the Plunkr to see what I'm working on. I have a dynamic tab control where each tab contains a component that extends from a 'Delay-load' component. The goal is for the user to click on a tab and then trigger the 'loadData&apo ...

Disable the movement and dragging functionality of the scroll feature in Google Maps using React

I have a map.jsx file in my React application that contains the code below: import React from 'react'; import GoogleMapReact from 'google-map-react'; import './map.css'; const Map = ({ location, zoomLevel }) => ( <d ...

Issue with the camera functionality in phonegap 3.3.0 API on IOS platform

I am currently in the process of developing an application for iPad that will allow users to capture and store photos. I have encountered some difficulties while using the PhoneGap camera API library, as my code is not generating any errors which makes i ...

Ensure that all elements are consistently kept within a DIV container

In my experience with web development, one recurring challenge is ensuring that everything stays contained within a div element. I often encounter situations where multiple nested divs and content cause styling nightmares when elements bleed out of their d ...

React - A guide on accessing the scroll position of a div using JavaScript

Within my side navigation bar, there is a title and other information. The title is fixed in place (sticky) and the sidebar has a height of 100vh. I am looking to add a box-shadow effect to the title div (sticky-title) only when the user scrolls down past ...

Altering information with the use of history.pushState throughout time

I've created a template that I want to load using the jQuery .load() function. However, during testing, I discovered that it's not loading at all. Here is the code I'm trying to use for loading: function open() { history.p ...

Load HTML content without having to refresh the page

I'm struggling to decide whether I should have the html hidden before it is loaded or pulled from another source. My goal is to display a form on one page and dynamic content on other pages. The form data needs to be saved in mongo db, and when the p ...

What is the best way to swap out the if else statement with a Ternary operator within a JavaScript function?

Is there a way to replace the if else statement in the function using a Ternary operator in JavaScript? private getProductName(productType: string): string { let productName = 'Product not found'; this.deal.packages.find(p => p.isSele ...

The use of findDOMNode has been marked as outdated in StrictMode. Specifically, findDOMNode was utilized with an instance of Transition (generated by MUI Backdrop) that is contained

I encountered the following alert: Alert: detectDOMNode is now outdated in StrictMode. detectDOMNode was given an instance of Transition which resides within StrictMode. Instead, attach a ref directly to the element you wish to reference. Get more inform ...

Creating a full-width input field with text aligned to the right:

.wrap { white-space: nowrap; } input { width: 100%; } body { /* just so you can see it overflowing */ border: 1px solid black; margin: 40px; padding: 10px; } <span class="wrap"><input type="text">.pdf</span> Observing the cod ...

Implementing jQuery slideDown effect on a nested table element

I am facing an issue where the nested table does not slide down from the top as intended when a user clicks the "Show" button. Despite setting the animation duration to 500ms with jQuery's slideDown() function, the table instantly appears. I am using ...

Verifying TypeScript Class Instances with Node Module Type Checking

My current task involves converting our Vanilla JS node modules to TypeScript. I have rewritten them as classes, added new functionality, created a legacy wrapper, and set up the corresponding Webpack configuration. However, I am facing an issue with singl ...

Transferring the chosen dropdown value to the following page

I am attempting to transfer the currently selected value from a dropdown to the next page using an HTTP request, so that the selected value is included in the URL of the subsequent page. The form dropdown element appears as follows: <form name="sortby ...

Experimenting with HTML and CSS to enhance email presentation

I am currently developing a Django application that requires sending out Emails with HTML templates. These email templates include images and dynamic variables from the Django context. However, each time I make changes to the inline CSS or HTML, I have t ...

Dynamic horizontal scrolling

I need help implementing a site using React that scrolls horizontally. I'm unsure how to implement certain aspects, so I am looking for some assistance. Within a wrapper, I have multiple container Divs. <div class="wrapper"> <div class=" ...

Problem with displaying information in the table based on the numerical input

How can I dynamically set the number of rows in a table based on an input field? var app = angular.module("myApp", []); app.controller("myCtrl", function($scope) { $scope.myObj =[ {"Name" : "Alfreds Futterkiste", "Country" : "Germany","City" : "Berlin ...