How to incorporate semantic HTML into React? - html

I'm pretty new to react and just want to get off on the right foot before I get deep into it and have to go back and change everything.
I'm wondering how to handle semantic html in react. Things like <header>, <nav>, <aside>, etc. I know these tags are important for accessibility reasons among other things, and I'd like to have that same kind of structure in my react app. I'm just not sure how to go about it. In reading online about it I see that <fragment> might be something I should use, but it doesn't seem to achieve the accessibility part of semantic html that I'd like to have.
How do you go about incorporating semantic html into react? And a possible second question, how does it work with components? If I have multiple components that each have a <header> or something, how does react compile that? Would I have a <header> and <footer> within each component? Or would my navbar component just be enclosed within <header> and my footer component would just be enclosed within <footer> and everything else would have its own <main>? At this point I feel like I'm overthinking it, but when I try to get started actually writing I get stuck.

It looks like you are indeed overthinking things.
React allows you to build and compose components using any type of valid HTML elements (semantic or not).
It's good practice to build accessible websites. With that in mind, you can have all sorts of semantics elements divided into components. These components can be Class components or Functional components (if you're using React Hooks they're all functional components).
Here's a quick example:
class App extends React.Component {
state = {
name: 'Amazing Startup'
}
render() {
return(
<React.Fragment>
<Header name={this.state.name}/>
<Main />
<Footer />
</React.Fragment>
)
}
}
function Header({ name }) {
return (
<header>
<h1>Hello! We are {name}</h1>
</header>
)
}
function Main() {
return (
<main>
<p>Important stuff goes here..</p>
</main>
)
}
function Footer() {
return (
<footer>
<p>Made with React - 1 Hacker Way Menlo Park, CA 94025</p>
</footer>
)
}
ReactDOM.render(<App />, document.getElementById('root'));
body {
font-family: sans-serif;
min-height: 100vh;
margin: 0;
}
#root {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr 2fr 1fr;
}
header {
font-size: 0.8rem;
background-color: deepskyblue;
padding: 0.5rem;
}
main {
background-color: limegreen;
padding: 0.5rem;
}
footer {
background-color: orange;
padding: 0.5rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
It's worth noting that you can definitely place all the required HTML elements inside a single component. However, it's nice to separate functionality, this in turn teaches you how to compose components, which is one of their main design principles.

all supported html attributes
JSX supports all html tags. All normal html semantics apply in react JSX.
Fragment
The React.Fragment component lets you return multiple elements in a
render() method without creating an additional DOM element
Correct react JSX syntax is each react component returns a single node, typically achieved like
render (
<div>
{ /* multiple children */ }
</div>
);
but this injects basically a useless div into the DOM. Fragment allows the following which won't pollute the DOM.
render (
<Fragment>
{ /* multiple children */ }
</Fragment>
);

Related

Stencil scoped styles nested

I'm not sure if this is possible but I don't know how to affect the scoped styles of a component inside another component.
We have the following components:
#Component({
tag: "gov-button",
styleUrl: "gov-button.scss",
shadow: false,
scoped: true
})
export class GovButton {
render() {
return (
<button class="element">
<slot name="left-icon"></slot>
<slot />
<slot name="right-icon"> </slot>
</button>
)
}
}
button.element {
slot::slotted(gov-icon) {
font-size: 3rem;
}
}
#Component({
tag: "gov-icon",
styleUrl: "gov-icon.scss",
shadow: false,
scoped: true
})
export class GovIcon {
render() {
return (
<span aria-hidden="true" class={this.name}></span>
)
}
}
span {
font-size: 1rem;
}
S následujícím použití
<gov-button variant="primary" size="small">
<gov-icon slot="left-icon" name="lightbulb"></gov-icon>
Small Primary
<gov-icon slot="right-icon" name="question"></gov-icon>
</gov-button>
I would like to affect the appearance of the gov-icon component in the gov-button.scss stylesheet, which is inserted into the gov-button component via a slot.
Unfortunately, with no selector I am not able to affect its appearance and I am not sure if it is even possible.
Thank you for help
I think this is because technically there are no slots in the Light DOM and Stencil only "emulates" them when scoped is on. Scoped CSS in Stencil means adding CSS classes based on component name (sc-gov-button and sc-gov-icon in your case) to your markup and modifying CSS selectors accordingly so they are "scoped" to these classes. This is why this doesn't work:
button.element {
slot::slotted(gov-icon) {
font-size: 3rem;
}
}
As a workaround, you can use the scoped icon selector in your button CSS instead:
.sc-gov-icon {
font-size: 3rem;
}
Of course it has its drawbacks such as that you need to update them when you change component names.
Take a look how they use scoped in Ionic - they use it only for a few components where they don't want Shadow DOM for performance reasons.

Export html from draft js editor and keeping the style

I am using draft js to create email templates in a reactJs application.
I implemented custom block types and with css I was able to align my columns properly (left, center, right). I used RichUtils to toggle block type.
However, my problem is when I am exporting the editor state into html, only the tags are exported, but I need the style too, so that the text-align style remains the same.
I use stateToHtml from draft-js-export-html when exporting the html.
I was also thinking about adding custom attributes, but I was not successful with it yet.
I appreciate every answer and thank you for the help in advance.
you can try this way:
import { ContentState, convertToRaw } from 'draft-js';
import draftToHtml from 'draftjs-to-html';
const currentContent = this.state.editorState.getCurrentContent();
return draftToHtml(convertToRaw(currentContent));
As an extension on #ArtemZubarev , there will be a problem when exporting it to html because it will contain no styles. So this requires 2 answers
How to get state to html: credits to #ArtemZubarev
import { ContentState, convertToRaw } from 'draft-js';
import draftToHtml from 'draftjs-to-html';
const currentContent = this.state.editorState.getCurrentContent();
return draftToHtml(convertToRaw(currentContent));
However, this will return unstyled elements, for example: <h1>Hello World</h1>.
This raises the question: How to keep the styling?
Option 1: CSS
Option 2: Create a render function that will inject the styles as inline
private injectHTML = (html?: string) => {
return `<!DOCTYPE html>
<html>
<head>
<style>
body {background-color: powderblue;}
h1 {color: blue;}
p {color: red;}
</style>
</head>
<body>
${
html
}
</body>
</html>`
}

web component - accept no child elements

How can I define a web component that works like <img> in that it accepts no child elements?
<script>
const QA = (q, d) => Array.prototype.slice.call((d||document).querySelectorAll(q), 0);
const QS = (q, d) => (d||document).querySelector(q);
</script>
<template id="push-message">
<style>
message { display: grid; font-family: sans-serif; background: #eee; outline: 1px solid; }
.badge { }
</style>
<message>
<img class="badge">
<img class="icon">
<img class="image">
</message>
</template>
<script>
const wpm = 'push-message';
customElements.define(wpm,
class extends HTMLElement {
constructor() {
super();
const l = QS(`#${wpm}`).content.cloneNode(true);
const s = this.attachShadow({ mode: 'open' }); s.appendChild(l);
}
QS(q) { return QS(q, this.shadowRoot); }
QA(q) { return QA(q, this.shadowRoot); }
static get observedAttributes() { return [ "badge", "icon", "image" ]; }
attributeChangedCallback(a, o, n) {
if (/^(badge|icon|image)$/.test(a))
this.QS(`.${a}`).src = n;
}
});
</script>
<push-message
badge="//google.com/favicon.ico"
icon="//google.com/favicon.ico"
image="//google.com/favicon.ico">
<p>ok</p>
DOM should be
<push-message></push-message>
<p></p>
not
<push-message><p></p></push-message>
and ok should display in the result.
Is there a way to change customElements.define to avoid having to explicitly close <push-message></push-message> and just use <push-message> but have it implicitly self-close?
Autonomous Custom Elements require a closing tag: Do custom elements require a close tag?
You can create a Customized Built-In Element extended from HTMLImageElement
to get a a self-closing IMG tag:
<img is="push-message" badge="//google.com/favicon.ico">
<img is="push-message" icon="//google.com/favicon.ico">
<img is="push-message" image="//google.com/favicon.ico">
<p>ok</p>
But an IMG can only have one src, so you might as well create 3 elements and use
<img is="message-badge">
<img is="message-icon">
<img is="message-image">
Self-closing tags as known as void elements.
AFAIK, it is not possible to create custom void elements. In summary, it needs changing browser HTML parsers which is not an easy thing to pull by the web community. Changes are required because of the way the browser implements a tag-soup algorithm.
Thus you will need a closing tag. You can read more about this here:
Specs discussion
Lit-html discussion
On a side note, if you have your own template compiler/parser like vue-compiler and ng-compiler, you can probably instruct it to understand self-closing custom elements at a build time. However, the benefits of achieving this are virtually non-existent.

Typescript Angular 5 add dynamically css to component

I have a really special issue. I am using AngularTS with C# on serverside and Typescript on clientside.
I want to add to our application the possibility, that the customer can add css styles in a textbox or add file locations (external).
In a custom component I want to add the html code from the official site of the customer. The customer should add the css files or text in order to show the content on our page like the content of the official site.
Unfortunately I could not find a possibility to add the css files.
#Component({
selector: 'customer-footer',
templateUrl: './customer-footer.component.html'
styleUrls: getCSS()})
export function getCSS(): string [] {
var styles: string[] = [];
styles.push("https://");
return styles;}
This doesn't work because AOT is not compatible with static refs.
I tried to add the css Content in styles Tag (Body-Area):
<style type="text/css">
{{footerCSS}}</style>
My best result was to add a Object (css) in ngStyle to the displaying .
<div *ngIf="!fixedBottom"
[innerHtml]="footerHtml"
[ngStyle]="footerCSS"></div>
Unfortunately I could not find a way to convert css code like this one:
.flatWeatherPlugin {
font-size: inherit;
width: 100%;
}
.flatWeatherPlugin p, .flatWeatherPlugin h2, .flatWeatherPlugin h3, .flatWeatherPlugin ul, .flatWeatherPlugin li {
padding: 0;
margin: 0;
color: inherit;
}
To a functional object. Has someone an idea or a helpful message?
In typescript you can use this to load css dynamically
require('css/stylesheet.css')

Using Polymer.updateStyles with #apply mixin

I have a dynamically Polymer 2.0 application, but it doesn't seem to work with #apply.
I have CSS variables and mixins:
<custom-style>
<style>
html {
--content-background-colour: #fff;
--content-foreground-colour: var(--paper-grey-700);
--content-mixin: {
background-color: var(--content-background-colour);
color: var(--content-foreground-colour);
}
}
.content-one {
background-color: var(--content-background-colour);
color: var(--content-foreground-colour);
}
.content-two {
#apply --content-mixin
}
</style>
</custom-style>
Then I have themes that users can select and apply:
const theme = {
"--content-background-colour": "var(--paper-grey-800)",
"--content-foreground-colour": "var(--paper-grey-100)"
};
Polymer.updateStyles(theme);
The problem is that only the direct variables update, those set with #apply don't. class="content-one" works, class class="content-two" fails.
What am I doing wrong and how do I dynamically change the styles of mixins?
Polymer still seems to be using same polyfill for variables and mixins that they were using in 1.x, which means dynamic style updating should only be limited to variables and should not work for mixins.
One way you can achieve dynamic styling is by adding and removing classes.