Categories
Angular JavaScript

A guide to styling Angular Components

Angular is a popular front-end framework made by Google. Like other popular front-end frameworks, it uses a component-based architecture to structure apps.

In this article, we’ll look at ways to style Angular components.

Component Styles

Angular components are styled with CSS. Everything about CSS applies to Angular components.

We can also compound component styles with components, which allows for more modular designs than regular stylesheets.

Using Component Styles

We can define CSS styles in addition to template content in our components.

One way to do it is to use the styles property in our component.

For example, we can write that as follows:

app.component.ts :

import { Component } from "@angular/core";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styles: [  
    `  
      h1 {  
        font-size: 50px;  
      }  
    `  
  ]  
})  
export class AppComponent {}

app.component.html :

<h1>Foo</h1>

Then we should see ‘Foo’ that’s 50 pixels big on the screen.

Styles in styles isn’t inherited by any components nested within the template or any content projected into the component.

We can use CSS class names and selectors that make the most sense in each component.

Class names and selectors don’t collide with class names and selectors in other parts of the app.

Changes elsewhere in the app don’t affect changes in the current component.

We can co-locate the CSS code of each component with TypeScript and HTML code of the component, which makes the project structure cleaner.

Also, we can change or remove CSS code without searching through the whole app to find where else the code is used.

Special Selectors

Angular apps can use special selectors to style components.

They come from selectors for styling the shadow DOM.

:host

The :host pseudoclass selector targets styles in the element that hosts the component rather than the elements inside the component’s template.

For example, we can write:

:host {  
  display: block;  
  border: 3px solid black;  
}

We can style host styles with the given selector by using the function form as follows:

:host(.active) {  
  border-width: 1px;  
}

:host-context

We can use :host-context to apply styles on some condition outside of a component’s view.

It works the same way as the :host selector, which can use the function form.

It’ll look in ancestor components all the way up to the document root for the given selector.

For example, we can write:

:host-context(.theme-light) h2 {  
  background-color: #fff;  
}

/deep/, >>>, and ::ng-deep (Deprecated)

We can use /deep/, >>>, and ::ng-deep to apply styles to outside of the component by disabling view encapsulation for the rule.

For example, we can write:

:host /deep/ h3 {  
  font-weight: bold;  
}

Style Files in Component Metadata

We can set the styleUrls to point to a stylesheet file to style a component.

For example, we can write the following:

app.component.ts :

import { Component } from "@angular/core";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.css"]  
})  
export class AppComponent {}

app.component.css :

h1 {  
  font-size: 50px;  
}

app.component.html ;

<h1>Foo</h1>

In the code above, we put our styles in app.component.css and point our styleUrls to that file in app.component.ts .

We can specify more than one style file in both styles and styleUrls .

Template Inline Styles

We can put style tags in our templates to add template inline styles.

For example, we can write:

app.component.html :

<style>  
  h1 {  
    font-size: 50px;  
  }  
</style>  
<h1>Foo</h1>

The code above will set the h1’s font size to 50 pixels.

Template Link Tags

We can add link tags to templates to reference other styles.

For example, we can write the following code:

app.component.ts :

import { Component } from "@angular/core";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html"  
})  
export class AppComponent {}

app.component.html :

<link rel="stylesheet" href="./app.component.css" />  
<h1>Foo</h1>

We see that we removed the styleUrls from AppComponent and put a link tag to reference the CSS file.

The styles should be applied from the file we referenced in the link tag.

CSS @imports

We can import CSS files with the standard CSS @import rule.

For example, we can write the following code:

foo.css :

h1 {  
  font-size: 50px;  
}

app.component.css :

@import url("./foo.css");

app.component.html :

<h1>Foo</h1>

External and Global Style Files

We can add external global styles to angular.json to include them in the build.

To register a CSS file, we can put in the styles section, which is set to styles.css by default.

Non-CSS Style Files

Angular CLI supports building style files in SASS, LESS or Stylus.

We can specify those files in styleUrls with the appropriate extensions (.scss, .less, or .styl) as in the following example:

app.component.scss :

h1  {  
  font-size: 70px;  
}

app.component.html :

<h1>Foo</h1>

View Encapsulation

We can control how view encapsulation works by setting the encapsulation setting in out component code.

The following are the possibilities for view encapsulation:

  • ShadowDom view encapsulation uses the browser’s native shadow DOM implementation. The component’s styles are included in the Shadow DOM
  • Native view encapsulation uses the now deprecated version of the browser’s native shadow DOM implementation
  • Emulated is the default option. It emulates the behavior of the shadow DOM by preprocessing and renaming CSS code to effectively scope the CSS to the component’s view
  • None means that Angular does no view encapsulation. The styles are added to global styles.

We can change the encapsulation setting as follows:

app.component.ts :

import { Component, ViewEncapsulation } from "@angular/core";

@Component({  
  selector: "app-root",  
  templateUrl: "./app.component.html",  
  styleUrls: ["./app.component.scss"],  
  encapsulation: ViewEncapsulation.Native  
})  
export class AppComponent {}

Conclusion

We can use CSS to style Angular components. In addition, it supports SASS, LESS, and Stylus for styling.

By default, the scope of the styles is local to the component. However, we can change that to be different.

We can also include inline styles in our templates via the style and link tags.

Categories
JavaScript React

Introduction to React Hooks

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we’ll look at how to use React hooks to make function components smarter.

Introducing Hooks

Hooks are introduced with React 16.8.

We can use hooks to make function components keep and change dynamic states.

For example, we can write the following code to add a hook to our app:

import React from "react";  
import ReactDOM from "react-dom";
function App() {  
  const [count, setCount] = React.useState(0); 
  return (  
    <div>  
      <button onClick={() => setCount(count + 1)}>Count {count}</button>  
    </div>  
  );  
}

In the code above, we have the React.useState hook with the default 0 passed in. It returns an array with the state, which we called count , and a function to set the state, which is called setCount .

Then in the onClick handler of the button, we can the setCount function to update the count.

Other packages like React DOM also has to be updated to 16.8 or later.

React Native since 0.59 also supports hooks.

No Breaking Changes

Hooks are completely opt-in. They coexist with class components. Therefore, we don’t have to change any existing code. They’re also completely interoperable with class components.

Class components will be available in the future. They also don’t replace our knowledge of existing React concepts.

Why do we need Hooks

We can use gooks to reuse stateful logic without creating higher-order components or doing other things to change our component hierarchy.

Complex Components Become Hard to Understand

Complex components have many methods which are lifecycle hooks and also our own user-defined functions.

They all have a mix of unrelated logic. This makes it too easy to introduce bugs and inconsistencies.

It’s impossible to break them into smaller components because stateful logic is everywhere. It’s also hard to test them because of the complexity.

We can use hooks to split one component into smaller functions based on what’s related.

Classes are Confusing

We have to understand a lot about how JavaScript classes work, which is different from most languages since JavaScript classes are just syntactic sugar on top of its own prototypical inheritance model.

Also, we have to make sure the value of this is correct so we don’t introduce errors.

Classes can introduce patterns that make optimizations difficult. They don’t minify well and they make hot reloading flaky and unreliable.

Hooks are used without classes, so we don’t have to worry about any of these issues.

Gradual Adoption Strategy

We can create new components with hooks without affecting anything existing code.

Therefore, we can try them on non-critical parts of an app first.

Class components will be supported in the foreseeable future.

Conclusion

Hooks are the new way to keep dynamic states in function components.

We can use function components with hooks the same way that we write class components.

They coexist with existing class components and they’ll still be supported in the foreseeable future.

Hooks remove the confusion that arises from JavaScript classes and also let React minify the code by providing additional optimizations that can’t be done with classes.

Categories
Express JavaScript

Compress Express.js Responses with the Compression Middleware

Compressing our responses is a great way to speed up our Express app’s performance.

To do this, we can use the compression middleware.

In this article, we’ll look at the options available to us for compressing data and how to send a compressed response with it.

Adding the Middleware

We can install the package by running:

npm install compression

Then we can include it with:

const compression = require('compression');

Options

The compression middleware takes an options parameter, which is an object that can have the following properties:

chunkSize

The chunk size of the compressed output. Default is 16384 bytes or zlib.Z_DEFAULT_CHUNK , where zlib is the zlib Node package.

filter

A function that decides what kind of responses should be compressed. The function is called as filter(req, res) and should return true if the kind of response should be compressed and false if it shouldn’t.

The default function uses the compressible module to check if the res.getHeader('Content-Type') is compressible.

level

The compression level to apply The higher the level of compression, the longer it’ll take to complete.

The values range from 0 (no compression) to 9 (highest level of compression). -1 can be used to mean the default compression level, which is equivalent to level 6.

memLevel

This sets how much memory should be allocated for compression and is an integer ranging from 1 for the minimum level to 9 for the maximum.

Default is zlib.Z_DEFAULT_MEMLEVEL or 8.

strategy

This sets the compression algorithm. The value only differs in the compression ratio and doesn’t affect the content of the compressed output.

The following are available:

  • zlib.Z_DEFAULT_STRATEGY — used for normal data
  • zlib.Z_FILTERED — used for data produced by a filter. Filtered data consists mostly of small values with a random distribution. This algorithm is tuned to compressed these kinds of data better. This algorithm forces more Huffman coding.
  • zlib.Z_FIXED — use to prevent the use of dynamic Huffman codes
  • zlib.Z_HUFFMAN_ONLY — force Huffman encoding only
  • zlib.Z_RULE — limit match distances to one, This gives a compression ratio as good as Huffman only, but gives better compression for PNG data

threshold

The byte threshold for response body size before compression is considered for the response. The default 1kb . The value can be the number of bytes or any string applied by the bytes module.

windowBits

The default value is zlib.Z_DEFAULT_WINDOWBITS or 15.

.filter

The default filter function, which we can use to construct a custom filter function that extends the default action.

res.flush

A res.flush method is added to force partially compressed response to be flushed to the client.

Example

For example, we can use it as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const compression = require('compression');
const app = express();  
const shouldCompress = (req, res) => {  
  if (req.headers['x-no-compression']) {  
    return false  
  }  
  return compression.filter(req, res);  
}

app.use(bodyParser.json());  
app.use(compression({  
  filter: shouldCompress,  
  level: 7,  
}));

app.get('/', (req, res) => {  
  const foo = 'foo';  
  res.send(foo.repeat(3000));  
});

app.listen(3000);

In the code above, we add the compression middleware and specify some options.

We specified that we compress our responses when the x-no-compression header isn’t present.

Also, we changed the compression level.

With the x-no-compression header present, our response is 9KB. After compression is enabled by removing the x-no-compression header, the response is only 402 bytes.

As we can see, the difference is huge. This is because the text is repeated so it can just keep one part of it and then repeat it instead of storing the whole string.

Server-Sent Events

We can compress responses with server-sent events. To do this, we compress the content after a window of the output has been buffered.

Once we have that, then we can send the data to the client.

We can use the res.flush() method to send whatever is present to the client.

For example, we can write:

const express = require('express');  
const bodyParser = require('body-parser');  
const compression = require('compression');
const app = express();  
const shouldCompress = (req, res) => {  
  if (req.headers['x-no-compression']) {  
    return false  
  }  
  return compression.filter(req, res);  
}

app.use(bodyParser.json());  
app.use(compression({  
  filter: shouldCompress,  
  level: 7,  
}));

app.get('/', (req, res) => {  
  res.setHeader('Content-Type', 'text/event-stream');  
  res.setHeader('Cache-Control', 'no-cache');  
  const timer = setInterval(() => {  
    res.write('foo');  
    res.flush()  
  }, 2000) res.on('close', () => {  
    clearInterval(timer)  
  })  
});

app.listen(3000);

To send a text event stream to the client, then we should see foo on the screen added every 2 seconds.

Conclusion

The compression middleware is useful for compressing regular responses and server-sent event output.

We can set options like compression level, chunk size, etc.

Also, if we want to compress server-side events, we should call res.flush to send what’s what already buffered to the client compressed.

Categories
JavaScript React

Creating Accessible React Apps — Focus and Semantics

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we’ll look at how to create accessible React apps.

Why Accessibility?

We should create accessible apps so that they can be used by everyone.

Standards and Guidelines

The Web Content Accessibility Guidelines provide guidelines for creating accessible web sites.

Also, we have the Web Accessibility Initiative — Accessible Rich Internet Applications document contains guidelines for building fully accessible JavaScript widgets.

aria-* HTML attributes are fully supported in JSX. These attributes are kept as kebab-case as they’re in HTML.

Semantic HTML

HTML tags are named for their meanings. This means that they make sense for screen readers and other accessibility programs that parse web content.

This means that instead of using div to group elements, we should use Fragments instead so that our app doesn’t have extra div elements getting in the way of screen readers.

For example, we can add fragments to a component as follows:

function ListItem({ item }) {  
  return (  
    <Fragment>  
      <dt>{item.term}</dt>  
      <dd>{item.meaning}</dd>  
    </Fragment>  
  );  
}

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      items: [  
        { term: "coffee", meaning: "black drink" },  
        { term: "milk", meaning: "white drink" }  
      ]  
    };  
  } 

  render() {  
    return (  
      <dl>  
        {this.state.items.map(item => (  
          <ListItem item={item} key={item.id} />  
        ))}  
      </dl>  
    );  
  }  
}

Then we get the following HTML rendered:

<dl>  
  <dt>coffee</dt>  
  <dd>black drink</dd>  
  <dt>milk</dt>  
  <dd>white drink</dd>  
</dl>

As we can see, fragments do not produce any extra HTML but let us group elements together.

A shorthand or fragments are <> and </> . Therefore, we can rewrite the code above as follows:

function ListItem({ item }) {  
  return (  
    <>  
      <dt>{item.term}</dt>  
      <dd>{item.meaning}</dd>  
    </>  
  );  
}

We keep the rest of the code the same.

Then we get the same HTML rendered.

Accessible Forms

We should label forms to provide accessibility for all users.

To do this, we add a for attribute to label elements. In React, the for element represented by the htmlFor prop.

This applies to all form controls.

For example, we can do the following to add a htmlFor prop:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = { name: "" };  
  } 

  render() {  
    return (  
      <>  
        <label htmlFor="name">Name:</label>  
        <input type="text" name="name" value={this.state.name} />  
      </>  
    );  
  }  
}

In the code above, we have:

htmlFor="name"

to relate the label to the form field. The htmlFor value should be the same as the name value of the form control element.

The full accessibility guidelines are at:

Notifying the user of errors

Errors need to understood by users. The following guides tells us how to expose error text to screen readers:

Focus Control

We should only change or remove outlines by using CSS so that users can get the focused element even without seeing the outline.

Ways to Skip to Desired Content

Also, we should provide ways for users to skip to what they want to see or use.

We can implement that with internal page anchors and some styling.

We can also put important content in elements like main and aside so that they can be differentiated from other content.

Programmatically Managing Focus

In React, we can access DOM elements by using refs. This means that we can control when an element is in focus by calling DOM methods to focus an element.

For example, if we want to focus an element when the component is mounted in the DOM tree, we can call focus as follows:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.textInput = React.createRef();  
  } 

  componentDidMount() {  
    this.textInput.current.focus();  
  } 

  render() {  
    return <input type="text" ref={this.textInput} />;  
  }  
}

In the code above, we created a ref to access the DOM element by writing:

this.textInput = React.createRef();

In the input element, we have:

ref={this.textInput}

to associate the input element with the ref we created.

Then in the componentDidMount hook, we have:

this.textInput.current.focus();

to focus the input when the component mounts. this.textInput.current returns the input element, so that we can call the native focus method on it.

Conclusion

When creating React apps, we should have accessibility in mind.

This means that we should use semantic HTML tags so that all users can understand what a page has.

Also, we should provide ways for users to skip to the content that they want to see.

Finally, we can focus elements programmatically so that users can use inputs right away when focus is lost by regaining focus.

Categories
JavaScript Vue

Introduction to Vue.js Event Handling — More Modifiers

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

In this article, we’ll look at how to handle various events with Vue.js and modify an event handler’s behavior.

Key Modifiers

When listening to keyboard events, we often want to check for specific keys. To do this, we can add the key name as the modifier of the v-on directive.

For example, we can use it as follows:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    name: ""  
  },  
  methods: {  
    submit() {  
      alert(this.name);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <input v-model="name" v-on:keyup.enter="submit" />  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

The code above will watch for presses for the enter key when the input if focused. Then when we press Enter and release the key at that time, we’ll get whatever’s typed into the input displayed in the alert box.

v-on:keyup.enter=”submit” only checks for when the Enter key is released.

For key names that are more than one word, we convert it to kebab case.

For example, if we want to listen to the keyup event of the page up key, we write:

<input v-on:keyup.page-up="onPageUp">

Then when the page up key is released, onPageUp is called.

Key Codes

We can also pass the key code as the modifier of v-on . For example, if we want to listen to the event when the Enter key is released after it’s pressed, we can write the following:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    name: ""  
  },  
  methods: {  
    submit() {  
      alert(this.name);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <input v-model="name" v-on:keyup.13="submit" />  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

However, the use ofkeyCode events are deprecated so it may not be supported in new browsers.

Aliases for commonly used key codes are included in Vue. They include:

  • .enter
  • .tab
  • .delete (captures both “Delete” and “Backspace” keys)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

Some keys, like arrow keys and .esc have inconsistent values in IE9, so these built-in aliases should be preferred if our app supported IE9.

We can also define our own key code aliases as follows:

Vue.config.keyCodes.f3 = 114

Then we can use:

v-on:keyup.f3

in our app.

System Modifier Keys

Since Vue 2.1.0 or later, we can use modifier keys to trigger mouse or keyboard event listeners only when the corresponding modifier keys are pressed:

  • .ctrl
  • .alt
  • .shift
  • .meta

The meta key is the command key on Macintosh keyboards. On Windows keyboards, the meta key is the windows key. On Sun workstation keyboards, it’s solid diamond key.

For example, if we want Alt-S to be the shortcut key to display an alert with what we typed, we can write the following:

src/index.js :

new Vue({  
  el: "#app",  
  data: {  
    name: ""  
  },  
  methods: {  
    submit() {  
      alert(this.name);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <input v-model="name" @keyup.alt.83="submit" />  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

If we want an alert to pop up when we Ctrl-click on a button, we can write the following:

src/index.js :

new Vue({  
  el: "#app",  
  data: {},  
  methods: {  
    sayHi() {  
      alert("hi");  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  </head> <body>  
    <div id="app">  
      <button @click.ctrl="sayHi">Say Hi</button>  
    </div>  
    <script src="src/index.js"></script>  
  </body>  
</html>

Then we get an alert with the word ‘hi’ when we Ctrl-click on the Say Hi button.

The modifier keys have to pressed when the event is emitted in both cases. So in the examples above, Alt or Ctrl have to press in addition to what comes after it.

.exact Modifier

Since Vue 2.5.0, we can use the .exact modifier to control the exact combination of system modifiers needed to trigger an event.

For example:

<button @click.ctrl="onClick">A</button>

will run onClick only when Ctrl is pressed, and if we want to run a method only when Ctrl-click and no other keys are pressed, we can write:

<button @click.ctrl.exact="onCtrlClick">A</button>

Mouse Button Modifiers

Since Vue 2.2.0, the following mouse modifier events can be used:

  • .left
  • .right
  • .middle

They’ll triggered when a specific mouse button is pressed.

Conclusion

We can listen to one key action or a combination of key actions with key modifiers.

We can reference them by key code or aliases.

Key names that have more than one word have to be converted to kebab case.

We can also listen to exact key combinations with .exact and mouse button clicks with mouse key modifiers.