Comments (13)
@rajsite Thanks for putting this together. We're talking with Blazor engineers and will work towards a solution. This is obviously less than ideal.
from fluentui-blazor.
@atmgrifter00 That does look like a cleaner way to use the ::deep
workaround (ie not requiring a wrapping element) and is described in the Blazor docs as Child component support. Good find!
I updated my top-level issue description and my example branch to use that workaround.
@EisenbergEffect @javiercn it still very much feels like a workaround but it is probably the workaround worth documenting. 👍 (as a community member using FAST, I'm not at Microsoft / representative of the Blazor team)
Hopefully there is some pattern that blazor / asp.net can adopt to make this use-case more first class. There is issue dotnet/razor#7606, however another idea could be inspired from Angular.
In Angular the corresponding concept is having components vs directives. A component is a class with a template associated with it and a directive is a class without a template associated with it but instead with a selector associated with it. For our Angular fast web component wrappers we have defined Angular directives that match to the web components and can do Angulary behaviors (Angular Form participation, defining property mappings, etc).
Notice in the following example that the directive has a selector that it matches but does not instantiate a template:
/**
* Directive to provide Angular integration for the button.
*/
@Directive({
selector: 'nimble-button'
})
export class NimbleButtonDirective {
public get appearance(): ButtonAppearance {
return this.elementRef.nativeElement.appearance;
}
@Input() public set appearance(value: ButtonAppearance | ButtonAppearanceAttribute) {
this.renderer.setProperty(this.elementRef.nativeElement, 'appearance', value);
}
public get disabled(): boolean {
return this.elementRef.nativeElement.disabled;
}
@Input() public set disabled(value: BooleanValueOrAttribute) {
this.renderer.setProperty(this.elementRef.nativeElement, 'disabled', toBooleanProperty(value));
}
// contentHidden property intentionally maps to the content-hidden attribute
// eslint-disable-next-line @angular-eslint/no-input-rename
@Input('content-hidden') public set contentHidden(value: BooleanValueOrAttribute) {
this.renderer.setProperty(this.elementRef.nativeElement, 'contentHidden', toBooleanProperty(value));
}
// ...
public constructor(private readonly renderer: Renderer2, private readonly elementRef: ElementRef<Button>) {}
}
I could imagine a similar concept like that in Blazor / ASP.net that could apply for web components. @javiercn Does something like that already exist to support the built-in elements, ie div, span, etc that could be extended for web components (particularly as dotnet/razor#7606 was de-prioritized and doesn't seem to be making much progress)?
from fluentui-blazor.
The solution here will likely involve dotnet/razor#7606 since CSS isolation works at the file/component level. We can't allow you to pierce into the scope of a component unless that component explicitly allows it, which we don't really have a mechanism for.
One way to workaround this issue is to use the ::deep
selector within the consuming component and make the style scoped to the callsite, for example, if your component is wrapped within a div
do something like div::deep fluent-textfield
on your scoped css file.
from fluentui-blazor.
Original workaround using wrapped ::deep hidden, See the top level issue description for the most recent workaround not requiring a wrapper
> The solution here will likely involve [dotnet/razor#7606](https://github.com/dotnet/razor/issues/7606) since CSS isolation works at the file/component level. We can't allow you to pierce into the scope of a component unless that component explicitly allows it, which we don't really have a mechanism for. > > One way to workaround this issue is to use the `::deep` selector within the consuming component and make the style scoped to the callsite, for example, if your component is wrapped within a `div` do something like `div::deep fluent-textfield` on your scoped css file.So we use Blazor's ::deep combinator which is a Blazor-specific feature that gets compiled out. The fundamental bit of the workaround is that we won't rely on the class set on the FAST Razor component and instead rely on an immediate wrapper and the ::deep
selector to target the FAST web component child of the FAST Razor component.
So instead of the following (which does not work as expected):
Counter.razor.css:
.button-container { border: 1px solid red; }
.my-razor-button-scoped-css { margin: 16px; }
Counter.razor:
<div class="button-container">
<FluentButton class="my-razor-button-scoped-css" @onclick="IncrementCount">Click me - scoped css</FluentButton>
</div>
The following workaround using ::deep
and a wrapper element would accomplish a similar behavior:
Counter.razor.css:
.button-container { border: 1px solid red; }
.my-razor-button-scoped-css { display: contents; } /* Note: Set the wrapper to display contents so the child handles sizing behavior. We know this will target the immediate parent of the generated fluent-button. */
.my-razor-button-scoped-css ::deep fluent-button { margin: 16px; } /* Note: This selector is targeting the underlying FAST web component generated by the FAST Razor component. */
Counter.razor:
<div class="button-container">
<div class="my-razor-button-scoped-css"> <!-- Note: This wrapper div was added and is used to help build the ::deep selector targeting the generated fluent-button FAST web component. -->
<FluentButton @onclick="IncrementCount">Click me - scoped css</FluentButton>
</div>
</div>
This seems workable. I'm on the fence if this is much better than some of the other workarounds like global CSS since it's a lot of munging in the DOM hierarchy.
If we had to assume one of these workarounds would be used long-term (maybe until .NET 7 or later @javiercn ?) then it might be better to have the encapsulation this option provides despite the maintenance burden of putting wrappers over every FAST Razor component usage.
I'll put a link in the workarounds options above.
from fluentui-blazor.
I may be mistaken, but I believe we missed the one configuration that will actually solve this perceived issue, which is taking the original CSS and simply changing it to:
.button-container { border: 1px solid red; }
.my-web-component-button-scoped-css { margin: 16px; }
::deep .my-razor-button-scoped-css { margin: 16px; }
I've verified that this yields the expected behavior with no changes to the .razor file (thus, no wrappers are necessary). I think this behavior jives with how we should expect Blazor isolated CSS to work (since the class we're applying to the Blazor component is actually applied to an element inside what is essentially a child component), and I believe we can close this issue out. I think it would be good to let @rajsite comment further before doing so however.
from fluentui-blazor.
Unfortunately, ::deep
was removed from the standards track several years ago and is only implemented in Chromium-based engines for backwards compat. It is deprecated.
from fluentui-blazor.
@rajsite Is a fix for this issue planned for the next Blazor release?
from fluentui-blazor.
@EisenbergEffect Blazor has a ::deep
pseudo-selector in its implementation of scoped CSS, which is that this is talking about I think.
from fluentui-blazor.
@javiercn @EisenbergEffect, correct. As far as I know, the ::deep
pseudo-selector is a necessary, well-supported construct for Blazor apps, otherwise the official docs are in dire need of updating.
from fluentui-blazor.
Oh. Interesting. That is confusing since W3C had a selector with the same name in early versions of web components, which was intentionally removed...
from fluentui-blazor.
Yes...it's all horribly confusing, particularly since we've now been conditioned to not use that pseudo-selector in Angular apps, which was once their recommendation for crossing component boundaries.
from fluentui-blazor.
Well, if this fixes the issues, that's great. I'd like to keep this open until we maybe add some documentation around this scenario. Anyone here interested in adding a small section to the readme?
from fluentui-blazor.
I could imagine a similar concept like that in Blazor / ASP.net that could apply for web components. @javiercn Does something like that already exist to support the built-in elements, ie div, span, etc that could be extended for web components (particularly as dotnet/razor-tooling#7606 was de-prioritized and doesn't seem to be making much progress)?
I guess that concept is tagHelpers which aren't supported in Blazor.
from fluentui-blazor.
Related Issues (20)
- Communication Toast MissingMethodException after deployment to Static Web site HOT 4
- fix: @bind-Value doesn't update the UI when changing Items at the same time in FluentCombobox HOT 2
- feat: add the ability to specify a column width at the column level for the FluentDataGrid HOT 5
- Please create Rich Text Editor HOT 1
- fix: Button for responsive menu overlaps with profile menu in demo website HOT 1
- GlobalState is set to default on wasm startup HOT 16
- feat: Provide fragment to extend Profile Menu Button HOT 5
- Add DI Registration for IToastService, IMesssageService, IDialogServicedocs to the documentation HOT 1
- fix: FluentHorizontalScroll shows all elements and has no scroll button HOT 2
- fix: KeyCodeService in Microsoft.FluentUI.AspNetCore.Components.FluentDataGrid HOT 2
- fix: DataGrid GridTemplateColumns not working HOT 6
- Hello, some suggestions, hope to get discussion and help.
- fix: `Virtualize=true` conflicts with `Class="multiline-text"` in FluentDataGrid HOT 4
- fix: broken Disabled flag in FluentNavLink HOT 1
- Regression in Theme sample after update to 4.7,1 HOT 6
- feat: add horizontal nav menu component HOT 3
- Javascript error when loading Data Grid items with Virtualize Interactive server side rendering HOT 1
- fix(Microsoft.FluentUI.AspNetCore.Components): missing LEGAL.txt HOT 4
- Allow for FluentTextField to inherit font-weight HOT 7
- fix: Selected option retained ordinal position after items changed in FluentSelect HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fluentui-blazor.